【题目描述】
Joe觉得云朵很美,决定去山上的商店买一些云朵。商店里有n朵云,云朵被编号为1,2,…...,n,并且每朵云都有一个价值。但是商店老板跟他说,一些云朵要搭配来买才好,所以买一朵云则与这朵云有搭配的云都要买。
但是Joe的钱有限,所以他希望买的价值越多越好。
【输入】
第1行n,m,w,表示n朵云,m个搭配,Joe有w的钱。
第2~n+1行,每行ci,di表示i朵云的价钱和价值。
第n+2~n+1+m行,每行ui,vi,表示买ui就必须买vi,同理,如果买vi就必须买ui。
【输出】
一行,表示可以获得的最大价值。
【输入样例】
5 3 10 3 10 3 10 3 10 5 100 10 1 1 3 3 2 4 2
【输出样例】
1
【提示】
【数据范围】
30%的数据保证:n≤100
50%的数据保证:n≤1,000;m≤100;w≤1,000
100%的数据保证:n≤10,000;0≤m≤5000;w≤10,000
这题就是 并查集和01背包的组合出来的题,首先要把搭配一起的用并查集组合起来,那么最后求出的物品数量肯定<=n
注意在用结构体把值赋值给w v时一定要先路径压缩一下,这样就是父节点就是一个值了
很有意思的一题
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 1e4 + 10;
int p[N];
int w[N];
int c[N];
int f[N];
int n, m, s;
struct node
{
int c;
int w;
bool flag;
}num[N];
int findth(int x)
{
if (x == p[x]) return x;
return p[x] = findth(p[x]);
}
void unionn(int x, int y)
{
int xx = findth(x);
int yy = findth(y);
if (xx != yy) p[yy] = xx;
}
int cnt;
int ci[N];
int di[N];
int main()
{
scanf("%d %d %d", &n, &m, &s);
for (int i = 1;i <= n;i++) p[i] = i;
for (int i = 1;i <= n;i++) {
scanf("%d %d", &ci[i], &di[i]);
}
for (int i = 1;i <= m;i++) {
int x, y;
scanf("%d %d", &x, &y);
unionn(x, y);
}
for (int i = 1;i <= n;i++) {
findth(i);
}
for (int i = 1;i <= n;i++) {
num[p[i]].w += ci[i];
num[p[i]].c += di[i];
num[p[i]].flag = true;
}
for (int i=1;i<=n;i++){
if (num[i].flag) {
w[++cnt] = num[i].w;
c[cnt] = num[i].c;
}
}
for (int i = 1;i <= cnt;i++) {
for (int j = s;j >= w[i];j--) {
f[j] = max(f[j], f[j - w[i]] + c[i]);
}
}
printf("%d\n", f[s]);
return 0;
}