網絡流

網絡流

網絡流24題  上下界網絡流 最大權閉合子圖 
html

最新版模板:網絡

 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[M << 1]; int top = 1;
11 
12 int e[N], d[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, m, s, t;
84     scanf("%d%d%d%d", &n, &m, &s, &t);
85     for(int i = 1, x, y, z; i <= m; i++) {
86         scanf("%d%d%d", &x, &y, &z);
87         add(x, y, z);
88     }
89     printf("%d", solve(s, t));
90     return 0;
91 }
Dinic最大流
 1 #include <cstdio>
 2 #include <algorithm>
 3 #include <queue>
 4 #include <cstring>
 5 
 6 const int N = 5010, M = 1000010, INF = 0x3f3f3f3f;
 7 
 8 struct Edge {
 9     int nex, v, c, len;
10 }edge[M << 1]; int top = 1;
11 
12 int e[N], d[N], vis[N], pre[N], flow[N];
13 std::queue<int> Q;
14 
15 inline void add(int x, int y, int z, int w) {
16     top++;
17     edge[top].v = y;
18     edge[top].c = z;
19     edge[top].len = w;
20     edge[top].nex = e[x];
21     e[x] = top;
22 
23     top++;
24     edge[top].v = x;
25     edge[top].c = 0;
26     edge[top].len = -w;
27     edge[top].nex = e[y];
28     e[y] = top;
29     return;
30 }
31 
32 inline bool SPFA(int s, int t) {
33     memset(d, 0x3f, sizeof(d));
34     d[s] = 0;
35     flow[s] = INF;
36     vis[s] = 1;
37     Q.push(s);
38     while(!Q.empty()) {
39         int x = Q.front();
40         Q.pop();
41         vis[x] = 0;
42         for(int i = e[x]; i; i = edge[i].nex) {
43             int y = edge[i].v;
44             if(edge[i].c && d[y] > d[x] + edge[i].len) {
45                 d[y] = d[x] + edge[i].len;
46                 pre[y] = i;
47                 flow[y] = std::min(flow[x], edge[i].c);
48                 if(!vis[y]) {
49                     vis[y] = 1;
50                     Q.push(y);
51                 }
52             }
53         }
54     }
55     return d[t] < INF;
56 }
57 
58 inline void update(int s, int t) {
59     int temp = flow[t];
60     while(t != s) {
61         int i = pre[t];
62         edge[i].c -= temp;
63         edge[i ^ 1].c += temp;
64         t = edge[i ^ 1].v;
65     }
66     return;
67 }
68 
69 inline int solve(int s, int t, int &cost) {
70     int ans = 0;
71     cost = 0;
72     while(SPFA(s, t)) {
73         ans += flow[t];
74         cost += flow[t] * d[t];
75         update(s, t);
76     }
77     return ans;
78 }
79 
80 int main() {
81 
82     int n, m, s, t;
83     scanf("%d%d%d%d", &n, &m, &s, &t);
84     for(int i = 1, x, y, z, w; i <= m; i++) {
85         scanf("%d%d%d%d", &x, &y, &z, &w);
86         add(x, y, z, w);
87     }
88     int cost;
89     int ans = solve(s, t, cost);
90     printf("%d %d", ans, cost);
91     return 0;
92 }
EK最小費用最大流

若是隻要求最小費用,不要求最大流的話,在while(SPFA)中d[t]>0時break便可。例:九月的咖啡店  ide


下面咱們來看一道模板題:洛谷P3376 優化

 1 #include <cstdio>
 2 #include <queue>
 3 #include <algorithm>
 4 #include <cstring>
 5 using namespace std;
 6 const int N = 10010,M = 100010;
 7 struct Dinic
 8 {
 9     struct Edge 
10     {
11         int u,v,c,next;
12     }edge[M<<1];int top=1;
13     int e[N],deep[N],cur[N];
14     void add(int x,int y,int z)
15     {
16         top++;
17         edge[top].u=x;
18         edge[top].v=y;
19         edge[top].c=z;
20         edge[top].next=e[x];
21         e[x]=top;
22         top++;
23         edge[top].u=y;
24         edge[top].v=x;
25         edge[top].c=0;
26         edge[top].next=e[y];
27         e[y]=top;
28         return;
29     }
30     queue<int>Q;
31     bool BFS(int s,int t)
32     {
33         memset(deep,0,sizeof(deep));
34         while(!Q.empty()) Q.pop();
35         deep[s]=1;
36         Q.push(s);
37         while(!Q.empty())
38         {
39             int op=Q.front();
40             Q.pop();
41             for(int i=e[op];i;i=edge[i].next) if(edge[i].c)
42             {
43                 int ed=edge[i].v;
44                 if(deep[ed]) continue;
45                 deep[ed]=deep[op]+1;
46                 if(ed==t) return true;
47                 Q.push(ed);
48             }
49         }
50         return false;
51     }
52     int DFS(int op,int t,int maxF)
53     {
54         if(op==t) return maxF;
55         int ans=0,i=(cur[op]?cur[op]:e[op]);///當前弧優化
56         for(;i;i=edge[i].next) if(edge[i].c)
57         {
58             int ed=edge[i].v;
59             if(deep[ed]!=deep[op]+1) continue;///注意這裏,不加爆0
60             int temp=DFS(ed,t,min(maxF-ans,edge[i].c));
61             if(!temp) {deep[ed]=0;continue;} ///注意這裏,優化1/3速度
62             ans+=temp;
63             edge[i].c-=temp;
64             edge[i^1].c+=temp;
65             cur[op]=i;
66             if(ans==maxF) return ans;
67         }
68         cur[op]=0;
69         return ans;
70     }
71     int solve(int s,int t)
72     {
73         int ans=0;
74         while(BFS(s,t)) 
75         {
76             memset(cur,0,sizeof(cur));
77             ans+=DFS(s,t,0x7f7f7f7f);
78         }
79         return ans;
80     }
81 }dinic;
82 
83 int main()
84 {
85     int n,m,s,t;
86     scanf("%d%d%d%d",&n,&m,&s,&t);
87     int x,y,z;
88     while(m--) 
89     {
90         scanf("%d%d%d",&x,&y,&z);
91         dinic.add(x,y,z);
92     }
93     printf("%d",dinic.solve(s,t));
94     return 0;
95 }
最大流 Dinic

發現費用流的模板沒放...趕忙放一個先。ui

Dinic怎麼搞都會掛的奇慘無比,仍是用EK比較穩。this

這個模板是EK的。spa

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <queue>
  4 #include <algorithm>
  5 typedef long long LL;
  6 const int N = 5010, M = 50010;
  7 const LL INF = 1ll << 62;
  8 
  9 int n;
 10 
 11 struct Dinic {
 12     struct Edge {
 13         int v, nex;
 14         LL c, len;
 15         Edge(int v = 0, int nex = 0, LL c = 0, LL len = 0) {
 16             this->v = v;
 17             this->nex = nex;
 18             this->c = c;
 19             this->len = len;
 20         }
 21     }edge[M << 1]; int top;
 22     int e[N], vis[N], pre[N];
 23     LL dis[N], flow[N];
 24     Dinic() {
 25         top = 1;
 26         memset(e, 0, sizeof(e));
 27     }
 28     inline void add(int x, int y, LL z, LL len) {
 29         ++top;
 30         edge[top].v = y;
 31         edge[top].c = z;
 32         edge[top].len = len;
 33         edge[top].nex = e[x];
 34         e[x] = top++;
 35         edge[top].v = x;
 36         edge[top].c = 0;
 37         edge[top].nex = e[y];
 38         edge[top].len = -len; /// len
 39         e[y] = top;
 40         return;
 41     }
 42     inline bool SPFA(int s, int t) {
 43         for(int i = 1; i <= n; i++) {
 44             dis[i] = INF;
 45         }
 46         memset(vis, 0, sizeof(vis));
 47         memset(pre, 0, sizeof(pre));
 48         memset(flow, 0, sizeof(flow));
 49         dis[s] = 0;
 50         vis[s] = 1;
 51         flow[s] = INF;
 52         std::queue<int> Q;
 53         Q.push(s);
 54         while(!Q.empty()) {
 55             int x = Q.front();
 56             //printf("SPFA: %d\n", x);
 57             Q.pop();
 58             vis[x] = 0;
 59             for(int i = e[x]; i; i = edge[i].nex) {
 60                 int y = edge[i].v;
 61                 if(dis[y] > dis[x] + edge[i].len && edge[i].c) {
 62                     dis[y] = dis[x] + edge[i].len;
 63                     pre[y] = i;
 64                     flow[y] = std::min(flow[x], edge[i].c);
 65                     if(vis[y]) {
 66                         continue;
 67                     }
 68                     vis[y] = 1;
 69                     Q.push(y);
 70                 }
 71             }
 72         }
 73         return dis[t] < INF;
 74     }
 75     inline void update(int s, int t) {
 76         int i, temp = flow[t];
 77         while(t != s) {
 78             //printf("update: %d\n", t);
 79             i = pre[t];
 80             edge[i].c -= temp;
 81             edge[i ^ 1].c += temp;
 82             t = edge[i ^ 1].v;
 83         }
 84         return;
 85     }
 86     void solve(int s, int t, LL &maxF, LL &cost) {
 87         maxF = cost = 0;
 88         while(SPFA(s, t)){
 89             update(s, t);
 90             maxF += flow[t];
 91             cost += flow[t] * dis[t];
 92         }
 93         return;
 94     }
 95 }D;
 96 
 97 int main() {
 98     int m, s, t;
 99     scanf("%d%d%d%d", &n, &m, &s, &t);
100     int x, y;
101     LL z, len;
102     for(int i = 1; i <= m; i++) {
103         scanf("%d%d%lld%lld", &x, &y, &z, &len);
104         D.add(x, y, z, len);
105     }
106     LL a, b;
107     D.solve(s, t, a, b);
108     printf("%lld %lld", a, b);
109     return 0;
110 }
洛谷P3381 AC代碼

下面咱們來看一道裸題:洛谷P4001 bzoj1001 狼抓兔子rest

得出結論:無向圖只需把反向邊的流量也建爲z便可 。code

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

就是跑的有點慢......能夠建對偶圖轉最短路,不過我顯然沒有那個興致。 htm


下面咱們來看一道入門題:poj3498 March of the Penguins

題意:

一堆企鵝要碰面,如今有N塊冰塊,第i個冰塊座標爲(xi,yi),上面有企鵝ni個,能承受企鵝在上面起跳mi次,而且知道企鵝最大跳距離爲d。你要幫助企鵝找到全部可能的彙集地點。
冰塊 1 ≤ N ≤ 100
 0 ≤ ni ≤ 10, 1 ≤ mi ≤ 200

作法:由於n很小因此能夠支持咱們枚舉終點T。

咱們嘗試用一流量表示一隻penguin的去向。

把每一個冰塊拆點來限制mi

從S往入點連流量ni的邊。

入點向出點連流量mi的邊。

距離小於d的連流量INF的邊。

而後查看從S到T的入點是否滿流便可。

注意:

每次枚舉終點時把流量改回來。

空間開足。

點從0開始編號。

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

poj1149 PIGS

題意:

有 M 個豬圈,每一個豬圈裏初始時有若干頭豬。開始全部豬圈都是關閉的。依次來了 N 個顧客,每一個顧客分別會打開指定的幾個豬圈,從中買若干頭豬。每一個顧客分別都有他可以買的數量的上限。每一個顧客走後,他打開的那些豬圈中的豬,均可以被任意地調換到其它開着的豬圈裏,而後全部豬圈從新關上。  問總共最多能賣出多少頭豬。
1 <= N <= 100
1 <= M <= 1000

咱們嘗試用一流量表明一頭豬的去向。

因爲整個過程能夠由顧客來劃分紅N個階段,因此考慮分層圖。

購買的那幾個豬圈之間創建一箇中間點,做爲中轉站,向T連流量爲顧客購買力的邊。

S向第一層的點連流量爲初始豬數的邊。

各點在各層之間縱向連邊,流量INF。有中轉點就在中轉點那裏過一下,流量仍是INF。

而後輸出最大流便可。

優化建圖:咱們發現有不少層之間的INF鏈,每條鏈都縮爲一條邊。

 1 #include <cstdio>
 2 #include <queue>
 3 #include <cstring>
 4 const int N = 100100, M = 1000010, INF = 0x3f3f3f3f;
 5 
 6 struct Edge {
 7     int v, nex, f;
 8 }edge[M << 1]; int top = 1;
 9 
10 int e[N], d[N], nt, last[N];
11 
12 inline void add(int x, int y, int z) {
13     edge[++top].v = y;
14     edge[top].f = z;
15     edge[top].nex = e[x];
16     e[x] = top++;
17     edge[top].v = x;
18     edge[top].f = 0;
19     edge[top].nex = e[y];
20     e[y] = top;
21     return;
22 }
23 
24 inline bool BFS(int s, int t) {
25     memset(d, 0, sizeof(d));
26     std::queue<int> Q;
27     d[s] = 1;
28     Q.push(s);
29     while(!Q.empty()) {
30         int x = Q.front();
31         Q.pop();
32         for(int i = e[x]; i; i = edge[i].nex) {
33             int y = edge[i].v;
34             if(!edge[i].f || d[y]) {
35                 continue;
36             }
37             d[y] = d[x] + 1;
38             Q.push(y);
39         }
40     }
41     return d[t];
42 }
43 
44 inline int DFS(int x, int t, int maxF) {
45     if(x == t) {
46         return maxF;
47     }
48     int ans = 0;
49     for(int i = e[x]; i; i = edge[i].nex) {
50         int y = edge[i].v;
51         if(d[x] + 1 != d[y] || !edge[i].f) {
52             continue;
53         }
54         int temp = DFS(y, t, std::min(edge[i].f, maxF - ans));
55         if(!temp) {
56             d[y] = 0;
57         }
58         ans += temp;
59         edge[i].f -= temp;
60         edge[i ^ 1].f += temp;
61         if(ans == maxF) {
62             return ans;
63         }
64     }
65     return ans;
66 }
67 
68 inline int dinic(int s, int t) {
69     int ans = 0;
70     while(BFS(s, t)) {
71         ans += DFS(s, t, 0x7f7f7f7f);
72     }
73     return ans;
74 }
75 
76 int main() {
77     int m, n, S = N - 1, T = N - 2;
78     scanf("%d%d", &n, &m);
79     for(int i = 1, x; i <= n; i++) {
80         scanf("%d", &x);
81         add(S, i, x);
82         last[i] = i;
83     }
84     nt = n;
85     for(int i = 1, a, b, t, x; i <= m; i++) {
86         scanf("%d", &a);
87         t = ++nt;
88         for(int j = 1; j <= a; j++) {
89             scanf("%d", &x);
90             add(last[x], t, INF);
91             last[x] = t;
92         }
93         scanf("%d", &b);
94         add(t, T, b);
95     }
96     printf("%d", dinic(S, T));
97     return 0;
98 }
AC代碼

 SGU 326 Perspective 

這個OJ就是毒瘤...

題意:

NBA 某小組內有 N 支球隊,小組內以及小組間已經進行了若干場比賽。如今給出這 N 支球隊目前勝利的場數、還剩多少場沒有比(包括小組內和小組間)以及小組內任意兩支球隊之間還剩多少場沒有比,存在maze[i][j]中, 問可否合理安排剩下的全部比賽,使得球隊 1 最後勝利的場數至少大於等於小組內任何一支其餘球隊。
1 <= N <= 20

組外的隨便處理一下,跟1有關的也處理了。

如今只須要解決剩下的組內比賽了。

咱們嘗試用一流量表明勝一場。

那麼對於i與j之間的比賽,創建節點t。

S向t連流量爲a[i][j]的邊,t向i,j連流量爲a[i][j]的邊。

每一個隊表明的點向T連最大剩餘勝場的邊。

若 最大流 == 比賽場數 則輸出YES不然NO

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

poj3281 Dining

題意:

有F種食物和D種飲料,每種食物或飲料只能供一頭牛享用,且每頭牛隻享用一種食物和一種飲料。如今有N頭牛,每頭牛都有本身喜歡的食物種類列表和飲料種類列表,問最多能使幾頭牛同時享用到本身喜歡的食物和飲料。
1 ≤ F ≤ 100
1 ≤ D ≤ 100
1 ≤ N ≤ 100 

這個題有兩個匹配條件,怎麼辦?

奶牛放中間便可。兩邊是食物飲料。

而後奶牛還要拆點來限流爲1。

  1 #include <cstdio>
  2 #include <queue>
  3 #include <cstring>
  4 const int N = 1000, M = 100010, INF = 0x3f3f3f3f;
  5 
  6 struct Edge {
  7     int v, nex, f;
  8 }edge[M << 1]; int top = 1;
  9 
 10 int e[N], d[N], win[N], rest[N];
 11 int a[30][30];
 12 
 13 inline void add(int x, int y, int z) {
 14     edge[++top].v = y;
 15     edge[top].f = z;
 16     edge[top].nex = e[x];
 17     e[x] = top++;
 18     edge[top].v = x;
 19     edge[top].f = 0;
 20     edge[top].nex = e[y];
 21     e[y] = top;
 22     return;
 23 }
 24 
 25 inline bool BFS(int s, int t) {
 26     memset(d, 0, sizeof(d));
 27     std::queue<int> Q;
 28     d[s] = 1;
 29     Q.push(s);
 30     while(!Q.empty()) {
 31         int x = Q.front();
 32         Q.pop();
 33         for(int i = e[x]; i; i = edge[i].nex) {
 34             int y = edge[i].v;
 35             if(!edge[i].f || d[y]) {
 36                 continue;
 37             }
 38             d[y] = d[x] + 1;
 39             Q.push(y);
 40         }
 41     }
 42     return d[t];
 43 }
 44 
 45 inline int DFS(int x, int t, int maxF) {
 46     if(x == t) {
 47         return maxF;
 48     }
 49     int ans = 0;
 50     for(int i = e[x]; i; i = edge[i].nex) {
 51         int y = edge[i].v;
 52         if(d[x] + 1 != d[y] || !edge[i].f) {
 53             continue;
 54         }
 55         int temp = DFS(y, t, std::min(edge[i].f, maxF - ans));
 56         if(!temp) {
 57             d[y] = 0;
 58         }
 59         ans += temp;
 60         edge[i].f -= temp;
 61         edge[i ^ 1].f += temp;
 62         if(ans == maxF) {
 63             return ans;
 64         }
 65     }
 66     return ans;
 67 }
 68 
 69 inline int dinic(int s, int t) {
 70     int ans = 0;
 71     while(BFS(s, t)) {
 72         ans += DFS(s, t, 0x7f7f7f7f);
 73     }
 74     return ans;
 75 }
 76 
 77 int main() {
 78     int n, A, B;
 79     scanf("%d%d%d", &n, &A, &B);
 80     for(int i = 1, x, a, b; i <= n; i++) {
 81         scanf("%d%d", &a, &b);
 82         for(int j = 1; j <= a; j++) {
 83             scanf("%d", &x);
 84             add(x, i + A, 1);
 85         }
 86         for(int j = 1; j <= b; j++) {
 87             scanf("%d", &x);
 88             add(i + A + n, x + A + n + n, 1);
 89         }
 90         add(i + A, i + A + n, 1);
 91     }
 92     int S = A + B + n + n + 1;
 93     int T = S + 1;
 94     for(int i = 1; i <= A; i++) {
 95         add(S, i, 1);
 96     }
 97     for(int i = 1; i <= B; i++) {
 98         add(i + A + n + n, T, 1);
 99     }
100     printf("%d", dinic(S, T));
101     return 0;
102 }
AC代碼

如今咱們來看一個經典模型:棋盤車放置。

車能夠攻擊一行一列,問m * n的棋盤上最多能放置幾個車?

min(m,n)啊,這不是廢話......

那麼加上一些障礙物,再加上一些地方不能放呢?

咱們嘗試用一流量來表明一個車的放置。

而後把全部行和列抽象成點,每一個能放車的位置就在其所屬的行列之間連流量爲1的邊。

行列和ST之間連流量爲1的邊。

若是有車的攻擊沒法越過的障礙物,至關於把一行分紅了兩行。列同理。

例題:洛谷P1263 宮廷守衛  

  1 #include <cstdio>
  2 #include <queue>
  3 #include <algorithm>
  4 #include <cstring>
  5 
  6 const int N = 210, INF = 0x7f7f7f7f;
  7 
  8 struct Edge {
  9     int nex, v, c;
 10 }edge[N * N * 2]; int top = 1;
 11 
 12 int e[N * N], d[N * N], eg[N][N], G[N][N];
 13 std::pair<int, int> pr[N][N];
 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     top++;
 22     edge[top].v = x;
 23     edge[top].c = 0;
 24     edge[top].nex = e[y];
 25     e[y] = top;
 26     return;
 27 }
 28 
 29 inline bool BFS(int s, int t) {
 30     std::queue<int> Q;
 31     Q.push(s);
 32     memset(d, 0, sizeof(d));
 33     d[s] = 1;
 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] = 0;
 62             continue;
 63         }
 64         ans += temp;
 65         edge[i].c -= temp;
 66         edge[i ^ 1].c += temp;
 67         if(ans == maxF) {
 68             break;
 69         }
 70     }
 71     return ans;
 72 }
 73 
 74 inline int solve(int s, int t) {
 75     int ans = 0;
 76     while(BFS(s, t)) {
 77         ans += DFS(s, t, INF);
 78     }
 79     return ans;
 80 }
 81 
 82 int main() {
 83     int n, m;
 84     scanf("%d%d", &n, &m);
 85     for(int i = 1; i <= n; i++) {
 86         for(int j = 1; j <= m; j++) {
 87             scanf("%d", &G[i][j]);
 88         }
 89     }
 90 
 91     // prework
 92     int lm = 1;
 93     bool f = 0;
 94     for(int i = 1; i <= n; i++) { /// -
 95         if(f) {
 96             f = 0;
 97             lm++;
 98         }
 99         for(int j = 1; j <= m; j++) {
100             if(G[i][j] == 2 && f) {
101                 lm++;
102                 f = 0;
103             }
104             else {
105                 pr[i][j].first = lm;
106                 f = 1;
107             }
108         }
109     }
110     int t = 1;
111     f = 0;
112     for(int j = 1; j <= m; j++) {
113         if(f) {
114             f = 0;
115             t++;
116         }
117         for(int i = 1; i <= n; i++) {
118             if(G[i][j] == 2 && f) {
119                 t++;
120                 f = 0;
121             }
122             else {
123                 pr[i][j].second = t;
124                 f = 1;
125             }
126         }
127     }
128     // - : 1 ... lm     | : lm + 1 ... t
129     for(int i = 1; i <= n; i++) {
130         for(int j = 1; j <= m; j++) {
131             if(!G[i][j]) {
132                 eg[i][j] = top + 1;
133                 add(pr[i][j].first, pr[i][j].second + lm, 1);
134             }
135         }
136     }
137     int S = lm + t + 1;
138     int T = S + 1;
139     for(int i = 1; i <= lm; i++) {
140         add(S, i, 1);
141     }
142     for(int i = 1; i <= t; i++) {
143         add(lm + i, T, 1);
144     }
145 
146     int ans = solve(S, T);
147     printf("%d \n", ans);
148 
149     for(int i = 1; i <= n; i++) {
150         for(int j = 1; j <= m; j++) {
151             if(!G[i][j] && !edge[eg[i][j]].c) {
152                 printf("%d %d \n", i, j);
153             }
154         }
155     }
156 
157     return 0;
158 }
AC代碼

最後來一個總結:

網絡流主要就是各類建圖,基本靠背,見多識廣。

常見的有:直接把兩種事物分開連邊,天天/每一個位置建點,橫着流豎着流,比賽向雙方連邊流量表示勝場,行向列連邊,點向行列連邊,最小天數時天天加點加邊,拆點限流,一流量表明一人/一物,各類拆點,費用流解線性規劃費用與流量的平方有關拆成1357,先構造一組解而後網絡流(上下界)調整,混合圖歐拉回路(隨意定向)。

常見模型有:最大流,最小割,費用流,最大權閉合子圖(正負向源匯連邊求最小割),二分圖最大匹配(最大流),二分圖最小點覆蓋(最小割),二分圖最大獨立集(減去點覆蓋),DAG最少鏈覆蓋(n-轉二分圖最大匹配(邊數)),DAG最少可重鏈覆蓋(floyd傳遞連通性),DAG最長反鏈(DAG最大獨立集)(等於最少鏈覆蓋),上下界。

相關文章
相關標籤/搜索