【BZOJ2427】【HAOI2010】軟件安裝

原題:html

如今咱們的手頭有N個軟件,對於一個軟件i,它要佔用Wi的磁盤空間,它的價值爲Vi。咱們但願從中選擇一些軟件安裝到一臺磁盤容量爲M計算機上,使得這些軟件的價值儘量大(即Vi的和最大)。ios

可是如今有個問題:軟件之間存在依賴關係,即軟件i只有在安裝了軟件j(包括軟件j的直接或間接依賴)的狀況下才能正確工做(軟件i依賴軟件j)。幸運的是,一個軟件最多依賴另一個軟件。若是一個軟件不能正常工做,那麼它可以發揮的做用爲0。ide

咱們如今知道了軟件之間的依賴關係:軟件i依賴軟件Di。如今請你設計出一種方案,安裝價值儘可能大的軟件。一個軟件只能被安裝一次,若是一個軟件沒有依賴則Di=0,這時只要這個軟件安裝了,它就能正常工做。spa

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

 

解法很簡單,注意到軟件可能相互依賴,因此tarjan縮環而後樹上dp3d

這題我卡了一夜,老是90分code

而後翻博客htm

兩年前我是這樣寫的:照着AC代碼瞎改一通,過了可是沒想明白爲何blog

兩年後我又作了一樣的事情排序

對比兩份代碼發現

寫法一:每一個節點開始只有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
相關文章
相關標籤/搜索