洛谷P2762 太空飛行計劃問題

這題套路好深......沒想渠。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 }
AC代碼
相關文章
相關標籤/搜索