Codeforces 741B:Arpa's weak amphitheater and Mehrdad's valuable Hoses(01背包+并查集)
http://codeforces.com/contest/741/problem/B
题意:有 n 个人,每个人有一个花费 w[i] 和价值 b[i],给出 m 条边,代表第 i 和 j 个人是一个集合的,给出一个最大花费 w,如果一个集合的人不能同时选的话,那么只能选集合中的其中一个或者不选,问按照这样的规则选得的花费不超过 w 的最大价值是多少。
思路:一开始搞个带权并查集出来,后来还是蒙了。之后看原来是01背包,然而已经N久没见过背包了。。。先用并查集弄出集合,然后对每个集合中的元素进行01背包(选集合中的一个或者不选的情况),在集合弄完之后还要对整体进行01背包(选集合中的全部),这里用了下滚动数组。
1 #include <cstdio> 2 #include <algorithm> 3 #include <iostream> 4 #include <cstring> 5 #include <string> 6 #include <cmath> 7 #include <queue> 8 #include <vector> 9 using namespace std; 10 #define INF 0x3f3f3f3f 11 #define N 100010 12 int dp[2][1010]; 13 int fa[1010]; 14 int b[1010], w[1010]; 15 vector<int> vec[1010]; 16 17 int Find(int x) { 18 if(x == fa[x]) return x; 19 return fa[x] = Find(fa[x]); 20 } 21 22 int main() 23 { 24 int n, m, x; 25 scanf("%d%d%d", &n, &m, &x); 26 for(int i = 1; i <= n; i++) scanf("%d", w + i); 27 for(int i = 1; i <= n; i++) scanf("%d", b + i); 28 for(int i = 1; i <= n; i++) fa[i] = i; 29 for(int i = 0; i < m; i++) { 30 int u, v; 31 scanf("%d%d", &u, &v); 32 u = Find(u), v = Find(v); 33 if(u != v) fa[u] = v; 34 } 35 for(int i = 1; i <= n; i++) 36 vec[Find(i)].push_back(i); 37 int now = 0; 38 for(int i = 1; i <= n; i++) { 39 now = !now; 40 int ww = 0, bb = 0; 41 for(int j = 0; j <= x; j++) dp[now][j] = dp[!now][j]; 42 for(int j = 0; j < vec[i].size(); j++) { 43 int id = vec[i][j]; 44 int www = w[id], bbb = b[id]; 45 ww += www, bb += bbb; 46 for(int j = www; j <= x; j++) { // 在当前集合选一个最优 47 dp[now][j] = max(dp[now][j], dp[!now][j-www] + bbb); 48 } 49 } 50 for(int j = ww; j <= x; j++) { // 如果全部能丢进去 51 dp[now][j] = max(dp[now][j], dp[!now][j-ww] + bb); 52 } 53 } 54 int ans = 0; 55 for(int i = 0; i <= x; i++) ans = max(ans, dp[now][i]); 56 printf("%d\n", ans); 57 return 0; 58 }