本题智障题,就是只有智障才会写错的那种......
乍一看很像一道洛谷上很水的树形DP题“选课”。
But......
记得某NOI签到题中有这样一句话:
依赖关系不存在环(若有m(m≥2)个软件包A1,A2,A3,…,Am,其中A1依赖A2,A2依赖A3,A3依赖A4,……,Am−1依赖Am,而Am依赖A1,则称这m个软件包的依赖关系构成环)
本条件完全不适用于此题。
因为给出的依赖关系很可能出现环(这不柯学),所以在进行树形DP之前,要先用Tarjan把每个环缩点。之后我们就得到一个森林,再令n+1号结点为虚拟结点,为森林中每棵树的根结点共同的爸爸(好像有点奇怪,不管了)。
再进行树形DP即可。
注意数组的初始化。(不同的人写的初始化方式不同,当然,这个法则对智障也同样适用)
完了。
就这道题我数组处理的时候少写了个memset()后当场爆炸30分。(这30分咋来的我也不知道)
智障的代码,正因如此有99行:
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cstdlib> 5 #include <cmath> 6 using namespace std; 7 const int MAXN=205;//因为缩点所以要开2倍数组。 8 const int MAXM=505; 9 int n,m,f[MAXN][MAXM],g[MAXM],w[MAXN],v[MAXN],d[MAXN],bel[MAXN],deg[MAXN],siz[MAXN]; 10 int dfn[MAXN],low[MAXN],tot,stc[MAXN],top; 11 bool ins[MAXN],linked[MAXN][MAXN]; 12 int head[MAXN],ecnt; 13 struct Edge{ 14 int to,nxt; 15 }e[MAXN]; 16 void add_edge(int bg,int ed){ 17 ecnt++; 18 e[ecnt].nxt=head[bg]; 19 e[ecnt].to=ed; 20 head[bg]=ecnt; 21 } 22 void tarjan(int x){ 23 dfn[x]=low[x]=++tot; 24 stc[++top]=x; 25 ins[x]=1; 26 for(int i=head[x];i;i=e[i].nxt){ 27 int ver=e[i].to; 28 if(!dfn[ver]){ 29 tarjan(ver); 30 low[x]=min(low[x],low[ver]); 31 } 32 else if(ins[ver]){ 33 low[x]=min(low[x],low[ver]); 34 } 35 } 36 if(low[x]==dfn[x]){ 37 int temp=++n; 38 while(stc[top+1]!=x){ 39 bel[stc[top]]=temp; 40 ins[stc[top]]=0; 41 top--; 42 } 43 } 44 } 45 void dfs(int x){ 46 if(!head[x]){ 47 siz[x]=w[x]; 48 f[x][w[x]]=v[x]; 49 f[x][0]=0; 50 return; 51 } 52 int tot=0; 53 f[x][0]=0; 54 for(int i=head[x];i;i=e[i].nxt){ 55 int ver=e[i].to; 56 dfs(ver); 57 tot+=siz[ver]; 58 for(int j=min(tot,m);j>=0;j--) 59 for(int k=0;k<=siz[ver];k++){ 60 if(k>j) break; 61 f[x][j]=max(f[x][j],f[x][j-k]+f[ver][k]); 62 } 63 } 64 for(int i=0;i<=m;i++) g[i]=f[x][i]; 65 memset(f[x],0xcf,sizeof f[x]); 66 for(int i=w[x];i<=m;i++) f[x][i]=g[i-w[x]]+v[x]; 67 f[x][0]=0; 68 siz[x]=tot+w[x]; 69 } 70 int main(){ 71 scanf("%d%d",&n,&m); 72 int pren=n; 73 for(int i=1;i<=n;i++) scanf("%d",&w[i]); 74 for(int i=1;i<=n;i++) scanf("%d",&v[i]); 75 for(int i=1;i<=n;i++){ 76 scanf("%d",&d[i]); 77 add_edge(d[i],i); 78 } 79 for(int i=1;i<=pren;i++) 80 if(!dfn[i]) tarjan(i); 81 for(int i=1;i<=pren;i++){ 82 w[bel[i]]+=w[i]; 83 v[bel[i]]+=v[i]; 84 for(int j=head[i];j;j=e[j].nxt){ 85 int ver=e[j].to; 86 if(bel[i]!=bel[ver]&&!linked[bel[i]][bel[ver]]) 87 add_edge(bel[i],bel[ver]),linked[bel[i]][bel[ver]]=1,deg[bel[ver]]++; 88 } 89 } 90 for(int i=pren+1;i<=n;i++) 91 if(!deg[i]) add_edge(n+1,i); 92 memset(f,0xcf,sizeof f);//只有智障才会使用的初始化方式。 93 dfs(n+1); 94 int ans=0; 95 for(int i=0;i<=m;i++) 96 ans=max(ans,f[n+1][i]); 97 printf("%d\n",ans); 98 return 0; 99 }
erkokoko~