Time Limit: 10 Sec Memory Limit: 128 MB
Submit: 2119 Solved: 850
[Submit][Status][Discuss]
Description
现在我们的手头有N个软件,对于一个软件i,它要占用Wi的磁盘空间,它的价值为Vi。我们希望从中选择一些软件安装到一台磁盘容量为M计算机上,使得这些软件的价值尽可能大(即Vi的和最大)。
但是现在有个问题:软件之间存在依赖关系,即软件i只有在安装了软件j(包括软件j的直接或间接依赖)的情况下才能正确工作(软件i依赖软件j)。幸运的是,一个软件最多依赖另外一个软件。如果一个软件不能正常工作,那么它能够发挥的作用为0。
我们现在知道了软件之间的依赖关系:软件i依赖软件Di。现在请你设计出一种方案,安装价值尽量大的软件。一个软件只能被安装一次,如果一个软件没有依赖则Di=0,这时只要这个软件安装了,它就能正常工作。
Input
第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 )
Output
一个整数,代表最大价值。
Sample Input
3 10
5 5 6
2 3 4
0 1 1
Sample Output
5
解题思路
应该很好看出这是一道树上背包问题,但是光跑树上背包只能拿40分,是因为有可能出现环状,
就是几个点相互依赖,要选必须全选,所以我们考虑tarjan缩点,大点的体积等于所有点加起来,
权值同样。
代码
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 105;
const int MAXM = 505;
inline int rd(){
int x=0,f=1;char ch=getchar();
while(ch<'0' || ch>'9') {if(ch=='-') f=-1;ch=getchar();}
while(ch>='0' && ch<='9') {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
return x*f;
}
struct Edge{
int nxt,to;
}edge[MAXN];
int n,m,v[MAXN],w[MAXN],d[MAXN];
int dp[MAXN][MAXM],cost[MAXN],val[MAXN];
int head[MAXN],cnt,tot,dis[MAXN][MAXN];
int dfn[MAXN],low[MAXN],sta[MAXN],top,col[MAXN],num;
bool vis[MAXN],used[MAXN];
inline void add(int bg,int ed){
edge[++cnt].to=ed;
edge[cnt].nxt=head[bg];
head[bg]=cnt;
}
inline void Tarjan(int x){
dfn[x]=low[x]=++tot;
vis[x]=1;
sta[++top]=x;
for(register int i=head[x];i;i=edge[i].nxt){
int u=edge[i].to;
if(!dfn[u]){
Tarjan(u);
low[x]=min(low[x],low[u]);
}
else if(vis[u])
low[x]=min(low[x],dfn[u]);
}
if(low[x]==dfn[x]){
vis[x]=0;
col[x]=++num;
while(sta[top]!=x){
col[sta[top]]=num;
vis[sta[top--]]=0;
}
top--;
}
}
inline int DP(int x){
for(register int i=cost[x];i<=m;i++) dp[x][i]=val[x];
for(register int i=head[x];i;i=edge[i].nxt){
int u=edge[i].to;
DP(u);
for(register int j=m-cost[x];j>=0;j--)
for(register int k=0;k<=j;k++)
dp[x][j+cost[x]]=max(dp[x][j+cost[x]],dp[x][j+cost[x]-k]+dp[u][k]);
}
}
int main(){
n=rd();m=rd();
for(register int i=1;i<=n;i++) w[i]=rd();
for(register int i=1;i<=n;i++) v[i]=rd();
for(register int i=1;i<=n;i++) {
d[i]=rd();
add(d[i],i);
}
for(register int i=1;i<=n;i++) if(!dfn[i]) Tarjan(i);
// for(register int i=1;i<=n;i++) cout<<col[i]<<" ";
for(register int i=1;i<=n;i++){
cost[col[i]]+=w[i];val[col[i]]+=v[i];
// cout<<col[i]<<" "<<col[d[i]]<<endl;
for(register int j=head[i];j;j=edge[j].nxt)
if(col[i]!=col[edge[j].to])
dis[col[i]][col[edge[j].to]]=1,used[col[edge[j].to]]=1;
}
memset(head,0,sizeof(head));cnt=0;
for(register int i=1;i<=num;i++)
for(register int j=1;j<=num;j++)
if(dis[i][j]) add(i,j);
for(register int i=1;i<=num;i++) if(!used[i])
add(num+1,i);
DP(num+1);
// for(register int i=0;i<=num;i++) cout<<dp[n][i]<<" ";
printf("%d\n",dp[num+1][m]);
}