第一次接触分组背包,背包题目的类型果然多。当然这也是并查集与分组背包的双剑合璧,威力惊人。
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <vector> //容器的使用。
using namespace std;
vector<int>vv[1005];
vector<int>ss[1005];
int dp[1005];
int boot[1005];
int val[1005], cost[1005];
int find1(int i)
{
return boot[i]==i?i:boot[i] = find1(boot[i]); //寻根
}
int main()
{
int n, w, k, i, j, h;
int a, b;
while(~scanf("%d%d%d", &n, &w, &k))
{
for(i = 1; i <= n; i ++)
{
scanf("%d%d",&val[i],&cost[i]);
boot[i] = i;
vv[i].clear();
ss[i].clear();
}
for(i = 1; i <= k; i ++)
{
scanf("%d%d",&a, &b);
a = find1(a);
b = find1(b);
if(a != b )boot[a] = b;
}
for(i = 1; i <= n; i ++)
{
vv[find1(i)].push_back(i); //把互斥的都集中化。。
}
for(i = 1, k = 0; i <= n; i ++)
{
int len = vv[i].size();
if(len == 0 )continue;
k++;
for(j = 0; j < len; j ++)
ss[k].push_back(vv[i][j]); //再次规范化。。把没有与谁互斥的删掉,构成一棵棵树。
}
for(i = 1; i <= k; i ++) //最后利用分组背包(01背包的变形)
for(j = w; j >= 0; j --)
for(h = 0; h < ss[i].size(); h++)
{
if(j >= cost[ss[i][h]])
{
dp[j] = max(dp[j], dp[j - cost[ss[i][h]]]+val[ss[i][h]]);
}
}
printf("%d\n", dp[w]);
}
return 0;
}