這題套路好深......沒想渠。ios
題意:給你若干個設備,若干個任務。ide
每一個任務須要若干設備,設備可重複利用。spa
完成任務有錢,買設備要錢。3d
問最大總收益(能夠什麼任務都不作)。code
解:最大權閉合子圖。blog
對於一個有向圖,若是選擇了一個點,那麼就要選擇它的全部後繼節點。求最大權值和。ci
創建s,t,記全部正權值和爲sum。get
s向全部權值爲正的點連邊,流量爲權值。string
全部權值爲負的點向t連邊,流量爲權值的絕對值。it
對於全部邊,創建流量INF的邊。
答案即爲sum - 最小割。
證實:
你割的邊顯然只能與s或t相連。
若是割了s -> a,表示不選a。
若是割了b -> t,表示選b。
那麼若是你選了一個點c,那麼就沒割,那麼c的全部後繼節點確定都割了。
大概就是這樣...意會一下吧。
1 #include <cstdio> 2 #include <queue> 3 #include <algorithm> 4 #include <cstring> 5 #include <iostream> 6 #include <string> 7 8 const int N = 107, M = 1000010, INF = 0x3f3f3f3f; 9 10 struct Edge { 11 int nex, v, c; 12 }edge[M << 1]; int top = 1; 13 14 int e[N], d[N], use[N]; 15 std::queue<int> Q; 16 std::string str; 17 18 inline void add(int x, int y, int z) { 19 top++; 20 edge[top].v = y; 21 edge[top].c = z; 22 edge[top].nex = e[x]; 23 e[x] = top; 24 25 top++; 26 edge[top].v = x; 27 edge[top].c = 0; 28 edge[top].nex = e[y]; 29 e[y] = top; 30 return; 31 } 32 33 inline bool BFS(int s, int t) { 34 memset(d, 0, sizeof(d)); 35 d[s] = 1; 36 Q.push(s); 37 while(!Q.empty()) { 38 int x = Q.front(); 39 Q.pop(); 40 for(int i = e[x]; i; i = edge[i].nex) { 41 int y = edge[i].v; 42 if(!edge[i].c || d[y]) { 43 continue; 44 } 45 d[y] = d[x] + 1; 46 Q.push(y); 47 } 48 } 49 return d[t]; 50 } 51 52 int DFS(int x, int t, int maxF) { 53 if(x == t) { 54 return maxF; 55 } 56 int ans = 0; 57 for(int i = e[x]; i; i = edge[i].nex) { 58 int y = edge[i].v; 59 if(!edge[i].c || d[x] + 1 != d[y]) { 60 continue; 61 } 62 int temp = DFS(y, t, std::min(edge[i].c, maxF - ans)); 63 if(!temp) { 64 d[y] = INF; 65 } 66 ans += temp; 67 edge[i].c -= temp; 68 edge[i ^ 1].c += temp; 69 if(ans == maxF) { 70 break; 71 } 72 } 73 return ans; 74 } 75 76 inline int solve(int s, int t) { 77 int ans = 0; 78 while(BFS(s, t)) { 79 ans += DFS(s, t, INF); 80 } 81 return ans; 82 } 83 84 inline void read(int *a) { 85 getline(std::cin, str); 86 a[0] = 0; 87 int len = str.size(); 88 int f = 0; 89 for(int i = 0; i < len; i++) { 90 if(str[i] < '0' || str[i] > '9') { 91 f = 0; 92 } 93 else { 94 if(!f) { 95 f = 1; 96 a[++a[0]] = str[i] - '0'; 97 } 98 else { 99 (a[a[0]] *= 10) += str[i] - '0'; 100 } 101 } 102 } 103 return; 104 } 105 106 int main() { 107 int m, n, sum = 0; 108 scanf("%d%d", &m, &n); 109 int s = m + n + 1, t = n + m + 2; 110 for(int i = 1, x; i <= m; i++) { 111 scanf("%d", &x); 112 add(s, i, x); 113 read(use); 114 for(int j = 1; j <= use[0]; j++) { 115 add(i, m + use[j], INF); 116 } 117 sum += x; 118 } 119 for(int i = 1, x; i <= n; i++) { 120 scanf("%d", &x); 121 add(m + i, t, x); 122 } 123 124 int ans = solve(s, t); 125 for(int i = 1; i <= m; i++) { 126 if(d[i]) { 127 printf("%d ", i); 128 } 129 } 130 puts(""); 131 for(int i = 1; i <= n; i++) { 132 if(d[i + m]) { 133 printf("%d ", i); 134 } 135 } 136 printf("\n%d", sum - ans); 137 return 0; 138 }