题目传送门:
思路:
这个题目的思路还算简单,就是用并查集来维护那些云要一起买。之后将要在一起买的云合并成一朵大云。之后就是一个简单的01背包问题了。
要注意的地方:
这个题目我居然WA了好几次,每次都是因为在枚举每个云判断是否属于同一个云的时候,没有将 f[i]
更新为 f[i]
的父亲导致 f[i]
中存的不是 \(i\) 所在的连通块的根。然后就WA了。
代码:
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
const int N = 1e4 + 5;
int n, m, v;
int a, b;
int c[N], w[N];
int f[N]; //并查集
int dp[N];
int read() {
int s = 0, w = 1;
char ch = getchar();
while (ch < '0' || ch > '9') {
if (ch == '-') w = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
s = s * 10 + ch - '0';
ch = getchar();
}
return s * w;
}
void write(int x) {
if (x < 0) putchar('-'), x = -x;
if (x > 9) write(x / 10);
putchar(x % 10 + '0');
}
int get_f(int v) {
if (f[v] == v) return v;
else return f[v] = get_f(f[v]);
}
inline int Max(int x, int y) {
return x >= y ? x : y;
}
int main(int argc, char const *argv[]) {
n = read(), m = read(), v = read();
for (register int i = 1; i <= n; ++i) {
c[i] = read(), w[i] = read();
f[i] = i; //初始化并查集
}
for (register int i = 1; i <= m; ++i) {
a = read(), b = read();
int t1 = get_f(a);
int t2 = get_f(b);
if (t1 != t2) f[t1] = t2;
}
for (register int i = 1; i <= n; ++i) {
f[i] = get_f(i);
if (f[i] != i) {
c[f[i]] += c[i];
w[f[i]] += w[i];
c[i] = 0;
w[i] = 0;
}
}
for (register int i = 1; i <= n; ++i) {
for (register int j = v; j >= c[i]; --j) {
dp[j] = Max(dp[j], dp[j - c[i]] + w[i]);
}
}
write(dp[v]), putchar('\n');
return 0;
}