#include using namespace std; const int N = 10010; int n, m, sum; //有 n 朵云,m 个搭配,Joe有 sum 的钱。 int v[N], w[N]; //表示 i 朵云的价钱和价值 int p[N]; int f[N][N]; /*过掉7/11个数据,无法AC 原因分析:f[N][N]第一维是可以选择的物品个数,上限是10000; 第二维是可以支付的钱数,上限也是10000; 如果按二维思路来处理,确实需要一个10000*10000的数组 10000*10000*8= 800000000 byte 800000000/1024/1024= 762MB 本题上限是64MB,妥妥的超内存,MLE~ 穷则思变,既然int+二维过不了,那么试试short吧,因为short最大是65536,符合题意, 并且只占两个bit,就是10000*10000*2= 200000000 byte 200000000/1024/1024= 190MB 本题上限是64MB,妥妥的超内存,MLE~ 那么一维的为什么可以呢? 一维的只有10000*8=80000 byte 80000/1024/1024=0.076MB 本题上限是64MB,肯定不会在内存上出问题。 总结: (1)01背包一维相比二维,能够节约非常大的空间,二维特别容易MLE。 (2)01背包一维相比二维,不用考虑上一个依赖是不是i-1行的问题,不用特殊用last方式 记录并处理,出错概率小 */ //最简并查集 int find(int x) { if (p[x] != x) p[x] = find(p[x]); //路径压缩 return p[x]; } int main() { cin >> n >> m >> sum; //实始化并查集 for (int i = 1; i <= n; i++) p[i] = i; //读入每个云朵的价钱(体积)和价值 for (int i = 1; i <= n; i++) cin >> v[i] >> w[i]; while (m--) { int a, b; cin >> a >> b; //两种云朵需要一起买 int pa = find(a), pb = find(b); if (pa != pb) { //集合有两个属性:总价钱、总价值,都记录到root节点上 v[pb] += v[pa]; w[pb] += w[pa]; p[pa] = pb; } } // 01背包 int last = 0; for (int i = 1; i <= n; i++) if (p[i] == i) { //因处理集合的代表元素 for (int j = 1; j <= sum; j++) { f[i][j] = f[last][j]; if (v[i] <= j) f[i][j] = max(f[i][j], f[last][j - v[i]] + w[i]); } last = i; //依赖的上一个状态 } printf("%d\n", f[n][sum]); return 0; }