【BZOJ2427】【HAOI2010】软件安装

原题:

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

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

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

n<=100,m<=500,wi<=m,vi<=1000

解法很简单,注意到软件可能相互依赖,所以tarjan缩环然后树上dp

这题我卡了一晚上,总是90分

然后翻博客

两年前我是这样写的:照着AC代码瞎改一通,过了但是没想明白为什么

两年后我又做了同样的事情

对比两份代码发现

写法一:每个节点开始只有f[w[i]]=v[i]其余为-oo,然后f[father[x]][i]=max(f[father[x]][i],f[father[x]][i-j]+f[x][j])

写法二:开始所有f[i][j]为0,然后f[father[x]][i]=max(f[father[x]][i],f[father[x]][i-j]+f[x][j]),最后

for(int i=m;i>=w[x];--i) f[x][i]=f[x][i-w[x]]+v[x];

for(int i=0;i<w[x];++i) f[x][i]=0;

写法一90写法二100

继续研究发现,把写法一从f[i][w[i]]=v[i]改成f[i][j]=v[i](w[i]<=j<=m)就过了

要到数据,把两种初始化方法打表出来观察

终于发现!

缩点之后点的质量会大于包容量

然后越界了

代码:(因为一开始没有意识到要用拓扑排序或重新建图所以写得有点屎):

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<cstdio>
 5 #include<algorithm>
 6 using namespace std;
 7 int rd(){int z=0,mk=1;  char ch=getchar();
 8     while(ch<'0'||ch>'9'){if(ch=='-')mk=-1;  ch=getchar();}
 9     while(ch>='0'&&ch<='9'){z=(z<<3)+(z<<1)+ch-'0';  ch=getchar();}
10     return z*mk;
11 }
12 struct edg{int y,nxt;}e[210];  int lk[110],ltp=0;
13 void ist(int x,int y){
14     e[++ltp]=(edg){y,lk[x]};  lk[x]=ltp;
15     //e[++ltp]=(edg){x,lk[y]};  lk[y]=ltp;
16 }
17 int n,m,a[110],b[110];  int fth[110];
18 int dfn[110],low[110],dft=0;
19 int q[110],hd=0;
20 int cid[110],ctp=0;
21 int c[110],d[110];
22 bool g[110][110];
23 int f[110][51000];  //!!!
24 bool vstd[110];
25 int nd[110];
26 int tth[110];
27 void tj(int x,int y){
28     dfn[x]=++dft;  low[x]=dfn[x];
29     q[++hd]=x;
30     for(int i=lk[x];i;i=e[i].nxt){//if(e[i].y!=y){
31         if(!dfn[e[i].y]){
32             tj(e[i].y,x);
33             low[x]=min(low[x],low[e[i].y]);
34         }
35         else if(!cid[e[i].y])
36             low[x]=min(low[x],low[e[i].y]);
37     }
38     if(dfn[x]==low[x]){
39         ++ctp;
40         int tmp=0;
41         for(;tmp!=x && hd;tmp=q[hd--]){
42             cid[q[hd]]=ctp;
43             c[ctp]+=a[q[hd]];
44             d[ctp]+=b[q[hd]];
45         }
46     }
47 }
48 void dfs(int x,int y){
49     vstd[x]=true;
50     f[x][c[x]]=d[x];
51     for(int i=lk[x];i;i=e[i].nxt)if(e[i].y!=y)
52         dfs(e[i].y,x);
53     for(int j=m;j>=0;--j)for(int k=0;j-k>=0;++k)
54         f[y][j]=max(f[y][j],f[y][j-k]+f[x][k]);
55 }
56 void prvs(){
57     ltp=0;
58     for(int i=1;i<=n;++i)  lk[i]=0;
59     for(int i=1;i<=n;++i)  dfn[i]=0;
60     hd=0;  ctp=0;
61     for(int i=1;i<=n;++i)  c[i]=0,d[i]=0;
62     for(int i=1;i<=n;++i)for(int j=1;j<=n;++j)  g[i][j]=false;
63     for(int i=0;i<=n;++i)for(int j=0;j<=m;++j)  f[i][j]=-1000000007;
64     //注意背包初值
65     for(int i=1;i<=n;++i)  vstd[i]=false;
66     for(int i=1;i<=n;++i)  nd[i]=0;
67 }
68 int main(){
69     //freopen("ddd.in","r",stdin);
70     cin>>n>>m;  prvs();
71     for(int i=1;i<=n;++i)  a[i]=rd();
72     for(int i=1;i<=n;++i)  b[i]=rd();
73     for(int i=1;i<=n;++i){
74         fth[i]=rd();
75         if(fth[i])  ist(i,fth[i]);
76     }
77     for(int i=1;i<=n;++i)if(!dfn[i])
78         tj(i,0);
79     for(int i=1;i<=n;++i)if(cid[i]!=cid[fth[i]])  tth[cid[i]]=cid[fth[i]];
80     n=ctp;
81     for(int i=1;i<=n;++i)  fth[i]=tth[i];
82     for(int i=1;i<=n;++i)if(fth[i])  ++nd[fth[i]];  //注意是有根树,只能用拓扑排序dp
83     hd=0;
84     for(int i=1;i<=n;++i)if(!nd[i])  q[++hd]=i;
85     f[0][0]=0;  //注意0节点初值
86     for(int i=1;i<=n;++i)  f[i][c[i]]=d[i];
87     //注意初始化的位置,不能在下面
88     for(int k=1;k<=hd;++k){
89         //f[q[k]][c[q[k]]]=d[q[k]];
90         for(int i=m;i>=0;--i)for(int j=0;i-j>=0;++j)
91             f[fth[q[k]]][i]=max(f[fth[q[k]]][i],f[fth[q[k]]][i-j]+f[q[k]][j]);
92         --nd[fth[q[k]]];
93         if(!nd[fth[q[k]]])  q[++hd]=fth[q[k]];
94     }
95     int ans=0;
96     for(int i=0;i<=m;++i)  ans=max(ans,f[0][i]);
97     cout<<ans<<endl;
98     return 0;
99 }
View Code

猜你喜欢

转载自www.cnblogs.com/cdcq/p/11735279.html
今日推荐