原題: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 }