题目描述
机器人们都想知道谁是最勇敢的,于是它们比赛搬运一些物品。
它们到了一个仓库,里面有n个物品,每个物品都有一个价值Pi和重量Wi,但是有些物品放在一起会爆炸,并且爆炸具有传递性。(a和b会爆炸、b和c会爆炸则a和c会爆炸)机器人们可不想因此损失自己好不容易从Wind那里敲诈来的装备,于是它们想知道在能力范围内,它们最多可以拿多少价值的物品。
你能帮助它们吗?
输入
每组测试数据
第1行为n,Wmax,k(0<=n,Wmax,k<=1000)
接下来n行,为每个物品的Pi,Wi(0<=Pi<=1000,1<=Wi<=10,均为整数)
再接下来k行,每行2个数字a,b表示a和b会发生爆炸
输出
对每组数据输出1行,为最大可能价值
样例输入 Copy
3 10 1
100 1
200 5
10 5
1 2
样例输出 Copy
210
思路
先用并查集将组分出来,用tot[i]记录第i个组有几件物品,ww[i][k]表示第i个组第k个物品的消耗,pp[i][k]表示第i组第k个物品的价值,然后套分组背包的板子就好啦。
代码
int n,m,k;
int p[maxn],w[maxn];
int fa[maxn];
int tot[maxn];//每个包里有多少个数
int dp[maxn];
int ww[maxn][maxn],pp[maxn][maxn];
int find(int x){
if(fa[x]==x)
return x;
return fa[x]=find(fa[x]);
}
void Union(int x,int y){
int fx=find(x);
int fy=find(y);
if(fx!=fy){
fa[fx]=fy;
}
}
vector<int>v[maxn];
int main(){
scanf("%d%d%d",&n,&m,&k);
for(int i=1;i<=n;i++){
cin>>p[i]>>w[i];
fa[i]=i;
}
int u,vv;
for(int i=1;i<=k;i++){
cin>>u>>vv;
Union(u,vv);
}
for(int i=1;i<=n;i++){
v[find(i)].push_back(i);
}
int cnt=0;
for(int i=1;i<=n;i++){
if(find(i)==i){//找到一个包
cnt++;
tot[cnt]=v[i].size();
int idx=0;
for(int j=0;j<v[i].size();j++){
idx++;
pp[cnt][idx]=p[v[i][j]];
ww[cnt][idx]=w[v[i][j]];
}
}
}
for(int i=1;i<=cnt;i++){//cnt个包
for(int j=m;j>=0;j--){//代价
for(int k=1;k<=tot[i];k++){
if(ww[i][k]<=j){//第i个包里的第k个物品
dp[j]=max(dp[j],dp[j-ww[i][k]]+pp[i][k]);
}
}
}
}
printf("%d\n",dp[m]);
}