|
|
#include <bits/stdc++.h>
|
|
|
|
|
|
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;
|
|
|
} |