[HAOI2010]软件安装(树形背包,tarjan缩点)
题目描述
现在我们的手头有N个软件,对于一个软件i,它要占用Wi的磁盘空间,它的价值为Vi。我们希望从中选择一些软件安装到一台磁盘容量为M计算机上,使得这些软件的价值尽可能大(即Vi的和最大)。
但是现在有个问题:软件之间存在依赖关系,即软件i只有在安装了软件j(包括软件j的直接或间接依赖)的情况下才能正确工作(软件i依赖软件j)。幸运的是,一个软件最多依赖另外一个软件。如果一个软件不能正常工作,那么它能够发挥的作用为0。
我们现在知道了软件之间的依赖关系:软件i依赖软件Di。现在请你设计出一种方案,安装价值尽量大的软件。一个软件只能被安装一次,如果一个软件没有依赖则Di=0,这时只要这个软件安装了,它就能正常工作。
输入输出格式
输入格式:
第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, ..., Dn (0<=Di<=N, Di≠i )
输出格式:
一个整数,代表最大价值
思路:
望过去满眼的树形DP
和前面写的选课一模一样,只是cost需要输入
但很显然,你会这样
为什么呢?
后来想了半天,才发现
如果1依赖于2,2依赖于2,3依赖于1的化,这几个个点其实也能选,不过要选得一起选
所以,我们要用tarjan来缩点
把所有满足上图关系的点变为一个新点,并且与0连边即可
Q:环套树怎么办?
因为一个点只唯一依赖另一个点,所以入边一定为1
所以一定是环到树,不可能树到环,所以缩点没问题
懒了一下,用了stl
代码:
// luogu-judger-enable-o2 #include<iostream> #include<stack> #include<cstdio> #include<cstring> #include<cstdlib> #define rii register int i #define rij register int j #define rik register int k using namespace std; const int N=105;const int M=505; struct E{ int to,nxt; }ed[N<<1]; int H[N<<1],cnt; stack<int>sta; bool ins[N]; int dp[N][M],v[N],w[N],d[N]; int tot,dfn[N],low[N]; int num,col[N],fv[N],fw[N]; int n,m,rd[N]; void add(int x,int y) { cnt++; ed[cnt].to=y; ed[cnt].nxt=H[x]; H[x]=cnt; return; } void read(int &in) { int x=0,f=1; char ch; for(ch=getchar();(ch<'0'||ch>'9')&&ch!='-';ch=getchar()); if(ch=='-') { f=-1; ch=getchar(); } while(ch>='0'&&ch<='9') { x=(x<<3)+(x<<1)+ch-'0'; ch=getchar(); } in=x*f; return; } void tarjan(int x) { dfn[x]=low[x]=++tot; ins[x]=true;sta.push(x); int t,k; for(rii=H[x];i;i=ed[i].nxt) { t=ed[i].to; if(!dfn[t]) { tarjan(t); low[x]=min(low[x],low[t]); } else if(ins[t]) { low[x]=min(low[x],dfn[t]); } } if(low[x]==dfn[x]) { num++; do { k=sta.top(); sta.pop(); col[k]=num; fw[num]+=w[k]; fv[num]+=v[k]; ins[k]=false; } while(k!=x); } return; } void dfs(int x) { for(rii=fw[x];i<=m;i++) { dp[x][i]=fv[x]; } int t; for(rii=H[x];i;i=ed[i].nxt) { t=ed[i].to; dfs(t); for(rij=m-fw[x];j>=0;j--) { for(rik=0;k<=j;k++) { dp[x][j+fw[x]]=max(dp[x][j+fw[x]],dp[x][j+fw[x]-k]+dp[t][k]); } } } return; } int main() { // freopen("software.in","r",stdin); // freopen("software.out","w",stdout); read(n); read(m); for(rii=1;i<=n;i++) { read(w[i]); } for(rii=1;i<=n;i++) { read(v[i]); } for(rii=1;i<=n;i++) { read(d[i]); if(d[i]) { add(d[i],i); } } for(rii=1;i<=n;i++) { if(!dfn[i]) { tarjan(i); } } memset(H,0,sizeof(H)); cnt=0; for(rii=1;i<=n;i++) { if(col[i]!=col[d[i]]&&d[i]) { add(col[d[i]],col[i]); rd[col[i]]++; } } for(rii=1;i<=num;i++) { if(!rd[i]) { add(num+1,i); } dfs(num+1); } printf("%d\n",dp[num+1][m]); return 0; }
1 // luogu-judger-enable-o2 2 #include<iostream> 3 #include<stack> 4 #include<cstdio> 5 #include<cstring> 6 #include<cstdlib> 7 #define rii register int i 8 #define rij register int j 9 #define rik register int k 10 using namespace std; 11 const int N=105;const int M=505; 12 struct E{ 13 int to,nxt; 14 }ed[N<<1]; 15 int H[N<<1],cnt; 16 stack<int>sta; 17 bool ins[N]; 18 int dp[N][M],v[N],w[N],d[N]; 19 int tot,dfn[N],low[N]; 20 int num,col[N],fv[N],fw[N]; 21 int n,m,rd[N]; 22 void add(int x,int y) 23 { 24 cnt++; 25 ed[cnt].to=y; 26 ed[cnt].nxt=H[x]; 27 H[x]=cnt; 28 return; 29 } 30 void read(int &in) 31 { 32 int x=0,f=1; 33 char ch; 34 for(ch=getchar();(ch<'0'||ch>'9')&&ch!='-';ch=getchar()); 35 if(ch=='-') 36 { 37 f=-1; 38 ch=getchar(); 39 } 40 while(ch>='0'&&ch<='9') 41 { 42 x=(x<<3)+(x<<1)+ch-'0'; 43 ch=getchar(); 44 } 45 in=x*f; 46 return; 47 } 48 void tarjan(int x) 49 { 50 dfn[x]=low[x]=++tot; 51 ins[x]=true;sta.push(x); 52 int t,k; 53 for(rii=H[x];i;i=ed[i].nxt) 54 { 55 t=ed[i].to; 56 if(!dfn[t]) 57 { 58 tarjan(t); 59 low[x]=min(low[x],low[t]); 60 } 61 else if(ins[t]) 62 { 63 low[x]=min(low[x],dfn[t]); 64 } 65 } 66 if(low[x]==dfn[x]) 67 { 68 num++; 69 do 70 { 71 k=sta.top(); 72 sta.pop(); 73 col[k]=num; 74 fw[num]+=w[k]; 75 fv[num]+=v[k]; 76 ins[k]=false; 77 } 78 while(k!=x); 79 } 80 return; 81 } 82 void dfs(int x) 83 { 84 for(rii=fw[x];i<=m;i++) 85 { 86 dp[x][i]=fv[x]; 87 } 88 int t; 89 for(rii=H[x];i;i=ed[i].nxt) 90 { 91 t=ed[i].to; 92 dfs(t); 93 for(rij=m-fw[x];j>=0;j--) 94 { 95 for(rik=0;k<=j;k++) 96 { 97 dp[x][j+fw[x]]=max(dp[x][j+fw[x]],dp[x][j+fw[x]-k]+dp[t][k]); 98 } 99 } 100 } 101 return; 102 } 103 int main() 104 { 105 // freopen("software.in","r",stdin); 106 // freopen("software.out","w",stdout); 107 read(n); 108 read(m); 109 for(rii=1;i<=n;i++) 110 { 111 read(w[i]); 112 } 113 for(rii=1;i<=n;i++) 114 { 115 read(v[i]); 116 } 117 for(rii=1;i<=n;i++) 118 { 119 read(d[i]); 120 if(d[i]) 121 { 122 add(d[i],i); 123 } 124 } 125 for(rii=1;i<=n;i++) 126 { 127 if(!dfn[i]) 128 { 129 tarjan(i); 130 } 131 } 132 memset(H,0,sizeof(H)); 133 cnt=0; 134 for(rii=1;i<=n;i++) 135 { 136 if(col[i]!=col[d[i]]&&d[i]) 137 { 138 add(col[d[i]],col[i]); 139 rd[col[i]]++; 140 } 141 } 142 for(rii=1;i<=num;i++) 143 { 144 if(!rd[i]) 145 { 146 add(num+1,i); 147 } 148 dfs(num+1); 149 } 150 printf("%d\n",dp[num+1][m]); 151 return 0; 152