bzoj 2427 && codevs 1866 tarjian缩点+树形dp

来源:互联网 发布:sql 创建表 id 自增 编辑:程序博客网 时间:2024/06/16 00:44

【题意】

2427: [HAOI2010]软件安装

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 929  Solved: 371
[Submit][Status][Discuss]

Description

现在我们的手头有N个软件,对于一个软件i,它要占用Wi的磁盘空间,它的价值为Vi。我们希望从中选择一些软件安装到一台磁盘容量为M计算机上,使得这些软件的价值尽可能大(即Vi的和最大)。

但是现在有个问题:软件之间存在依赖关系,即软件i只有在安装了软件j(包括软件j的直接或间接依赖)的情况下才能正确工作(软件i依赖软件j)。幸运的是,一个软件最多依赖另外一个软件。如果一个软件不能正常工作,那么它能够发挥的作用为0

我们现在知道了软件之间的依赖关系:软件i依赖软件Di。现在请你设计出一种方案,安装价值尽量大的软件。一个软件只能被安装一次,如果一个软件没有依赖则Di=0,这时只要这个软件安装了,它就能正常工作。

Input

1行:N, M 0<=N<=100, 0<=M<=500
      2行:W1, W2, ... Wi, ..., Wn 0<=Wi<=M
      3行:V1, V2, ..., Vi, ..., Vn  0<=Vi<=1000
      4行:D1, D2, ..., Di, ..., Dn0<=Di<=N, Di≠i

Output

一个整数,代表最大价值。

Sample Input

3 10
5 5 6
2 3 4
0 1 1

Sample Output

5
【解题方法】

观察样例容易知道,这是一堆点套着一个环,由于是有向图,可以缩点,缩点之后就是一个树形dp模板了,缩点不会,还特意去学了一下,可以参考这篇blog:点击打开链接

【AC 代码】

#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>using namespace std;const int maxn = 105;int n,m,tot,scc,ind,top;int v[maxn],w[maxn],sv[maxn],sw[maxn];int q[maxn],in[maxn*5];bool inq[maxn];int low[maxn],dfn[maxn],belong[maxn];int dp[maxn][maxn*5];int head1[maxn],head2[maxn];struct edge{    int to,next;}e1[maxn*5],e2[maxn*5];void init1(){    memset(head1,0,sizeof(head1));    tot=0;}void init2(){    memset(head2,0,sizeof(head2));    tot=0;}void addedge1(int u,int v){    e1[++tot].to=v,e1[tot].next=head1[u],head1[u]=tot;}void addedge2(int u,int v){    in[v]=1;    e2[++tot].to=v,e2[tot].next=head2[u],head2[u]=tot;}void tarjian(int x){    int now=0;    low[x]=dfn[x]=++ind;    q[++top]=x;inq[x]=1;    for(int i=head1[x]; i; i=e1[i].next){        int v=e1[i].to;        if(!dfn[v]){            tarjian(v);            low[x]=min(low[x],low[v]);        }else if(inq[v]){            low[x]=min(low[x],dfn[v]);        }    }    if(low[x]==dfn[x]){        scc++;        while(now!=x){            now=q[top--];inq[now]=0;            belong[now]=scc;            sv[scc]+=v[now];            sw[scc]+=w[now];        }    }}void rebuild(){    tot=0;    for(int x=1; x<=n; x++)    for(int i=head1[x]; i; i=e1[i].next)        if(belong[e1[i].to]!=belong[x])            addedge2(belong[x],belong[e1[i].to]);}void dfs(int x){    for(int i=head2[x]; i; i=e2[i].next){        int v=e2[i].to;        dfs(v);        for(int j=m-sw[x]; j>=0; j--){            for(int k=0; k<=j; k++){                dp[x][j] = max(dp[x][j],dp[x][k]+dp[v][j-k]);            }        }    }    for(int j=m; j>=0; j--){        if(j>=sw[x]) dp[x][j]=dp[x][j-sw[x]]+sv[x];        else dp[x][j]=0;    }}int main(){    scanf("%d%d",&n,&m);    for(int i=1; i<=n; i++) scanf("%d",&w[i]);    for(int i=1; i<=n; i++) scanf("%d",&v[i]);    init1();    for(int i=1; i<=n; i++){        int x;        scanf("%d",&x);        if(x) addedge1(x,i);    }    for(int i=1; i<=n; i++){        if(!dfn[i]) tarjian(i);    }    //init2();    rebuild();    for(int i=1; i<=scc; i++){        if(!in[i]) addedge2(scc+1,i);    }    dfs(scc+1);    cout<<dp[scc+1][m]<<endl;    return 0;}


0 0