洛谷P4843 清理雪道

題意:給你DAG,求最小路徑邊覆蓋。路徑可重。ide

解:首先能夠想到邊轉點,發現有n²條邊,果斷超時。spa

有源匯有上下界最小流。code

建圖:每條邊都創建一條邊,流量限制爲[1, 1]。blog

源點向每一個點連邊,由於均可以做爲起點。流量不限。string

每一個點向匯點連邊,同上。it

求最小可行流。io

首先去掉下界限制,跑出一個可行流。event

而後求t -> s的最大流,退掉多餘流。class

  1 #include <cstdio>
  2 #include <algorithm>
  3 #include <queue>
  4 #include <cstring>
  5 
  6 const int N = 10010, M = 1000010, INF = 0x3f3f3f3f;
  7 
  8 struct Edge {
  9     int nex, v, c;
 10 }edge[N << 1]; int top = 1;
 11 
 12 int e[N], d[N], ot[N];
 13 std::queue<int> Q;
 14 
 15 inline void add(int x, int y, int z) {
 16     top++;
 17     edge[top].v = y;
 18     edge[top].c = z;
 19     edge[top].nex = e[x];
 20     e[x] = top;
 21 
 22     top++;
 23     edge[top].v = x;
 24     edge[top].c = 0;
 25     edge[top].nex = e[y];
 26     e[y] = top;
 27     return;
 28 }
 29 
 30 inline bool BFS(int s, int t) {
 31     memset(d, 0, sizeof(d));
 32     d[s] = 1;
 33     Q.push(s);
 34     while(!Q.empty()) {
 35         int x = Q.front();
 36         Q.pop();
 37         for(int i = e[x]; i; i = edge[i].nex) {
 38             int y = edge[i].v;
 39             if(!edge[i].c || d[y]) {
 40                 continue;
 41             }
 42             d[y] = d[x] + 1;
 43             Q.push(y);
 44         }
 45     }
 46     return d[t];
 47 }
 48 
 49 int DFS(int x, int t, int maxF) {
 50     if(x == t) {
 51         return maxF;
 52     }
 53     int ans = 0;
 54     for(int i = e[x]; i; i = edge[i].nex) {
 55         int y = edge[i].v;
 56         if(!edge[i].c || d[x] + 1 != d[y]) {
 57             continue;
 58         }
 59         int temp = DFS(y, t, std::min(edge[i].c, maxF - ans));
 60         if(!temp) {
 61             d[y] = INF;
 62         }
 63         ans += temp;
 64         edge[i].c -= temp;
 65         edge[i ^ 1].c += temp;
 66         if(ans == maxF) {
 67             break;
 68         }
 69     }
 70     return ans;
 71 }
 72 
 73 inline int solve(int s, int t) {
 74     int ans = 0;
 75     while(BFS(s, t)) {
 76         ans += DFS(s, t, INF);
 77     }
 78     return ans;
 79 }
 80 
 81 int main() {
 82 
 83     int n;
 84     scanf("%d", &n);
 85     int s = n + 1, t = n + 2;
 86     for(int i = 1, x, y; i <= n; i++) {
 87         scanf("%d", &x);
 88         for(int j = 1; j <= x; j++) {
 89             scanf("%d", &y);
 90             add(i, y, INF);
 91             ot[i]++;
 92             ot[y]--;
 93         }
 94         add(s, i, INF);
 95         add(i, t, INF);
 96     }
 97     int ss = n + 3, tt = n + 4, sum = 0;
 98     for(int i = 1; i <= n; i++) {
 99         if(ot[i] > 0) {
100             add(i, tt, ot[i]);
101             sum += ot[i];
102         }
103         else if(ot[i] < 0) {
104             add(ss, i, -ot[i]);
105         }
106     }
107     add(t, s, INF);
108     solve(ss, tt);
109     int ans;
110     for(int i = e[s]; i; i = edge[i].nex) {
111         if(edge[i].v == t) {
112             ans = edge[i].c;
113             break;
114         }
115     }
116     for(int i = e[ss]; i; i = edge[i].nex) {
117         edge[i].c = edge[i ^ 1].c = 0;
118     }
119     for(int i = e[tt]; i; i = edge[i].nex) {
120         edge[i].c = edge[i ^ 1].c = 0;
121     }
122     edge[top].c = edge[top - 1].c = 0;
123 
124     ans -= solve(t, s);
125     printf("%d", ans);
126     return 0;
127 }
AC代碼

題外話:cli

一開始感受跟餐巾計劃問題很像,結果沒想出費用流作法......

餐巾計劃問題也沒想出上下界作法...

太菜了。

相關文章
相關標籤/搜索