经商
原题链接
https://ac.nowcoder.com/acm/problem/14545
思路
先用并查集维护一下所有从1能走到的点,每次给出两个点,就将这两个点的祖宗节点维护,最后对于所有的1到n号点,用01背包做一次,只要祖宗节点和1号点一样,就代表能走到,就可以放到背包考虑。
代码
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int N = 10010, M = 510;
int p[N];
int f[M]; // 表示考虑第i个人能获得的最大利益
int w[N], v[N];
int find(int x)
{
if (x != p[x]) p[x] = find(p[x]);
return p[x];
}
int main()
{
int t;
cin >> t;
while (t -- )
{
memset(f, 0, sizeof f);
int n, m, c;
cin >> n >> m >> c;
for (int i = 1; i <= n; i ++ ) p[i] = i;
for (int i = 2; i <= n; i ++ ) cin >> v[i] >> w[i];
for (int i = 1; i <= m; i ++ )
{
int a, b;
cin >> a >> b;
a = find(a), b = find(b);
if (a != b) p[b] = a;
}
for (int i = 2; i <= n; i ++ )
{
if (find(i) == find(1)) // 写find因为1可能被加到别的点后面
for (int j = c; j >= v[i]; j -- )
f[j] = max(f[j], f[j - v[i]] + w[i]);
}
cout << f[c] << endl;
}
return 0;
}