网络流24题

  1. 飞行员配对问题(二分图匹配模板)

  1 #include <iostream>
  2 #include <string.h>
  3 #include <cstdio>
  4 #include <vector>
  5 #include <stack>
  6 #include <math.h>
  7 #include <string>
  8 #include <algorithm>
  9 
 10 #define SIGMA_SIZE 26
 11 #define lson rt<<1
 12 #define rson rt<<1|1
 13 #define lowbit(x) (x&-x)
 14 #define fode(i, a, b) for(int i=a; i>=b; i--)
 15 #define foe(i, a, b) for(int i=a; i<=b; i++)
 16 #define fod(i, a, b) for(int i=a; i>b; i--)
 17 #define fo(i, a, b) for(int i=a; i<b; i++)
 18 //#pragma warning ( disable : 4996 )
 19 
 20 using namespace std;
 21 typedef long long LL;
 22 inline LL LMax(LL a, LL b) { return a>b ? a : b; }
 23 inline LL LMin(LL a, LL b) { return a>b ? b : a; }
 24 inline LL lgcd(LL a, LL b) { return b == 0 ? a : lgcd(b, a%b); }
 25 inline LL llcm(LL a, LL b) { return a / lgcd(a, b)*b; }  //a*b = gcd*lcm
 26 inline int Max(int a, int b) { return a>b ? a : b; }
 27 inline int Min(int a, int b) { return a>b ? b : a; }
 28 inline int gcd(int a, int b) { return b == 0 ? a : gcd(b, a%b); }
 29 inline int lcm(int a, int b) { return a / gcd(a, b)*b; }  //a*b = gcd*lcm
 30 const LL INF = 0x3f3f3f3f3f3f3f3f;
 31 const LL mod = 998244353;
 32 const double eps = 1e-8;
 33 const int inf = 0x3f3f3f3f;
 34 const int maxk = 1e6+5;
 35 const int maxn = 1e4+10;
 36 
 37 struct node{
 38     int to, next;
 39 }e[maxn];
 40 int w, y,  cnt;
 41 int linjie[210], match[210];
 42 bool vis[210];
 43 
 44 void addedge(int u, int v)
 45 { e[cnt].to=v; e[cnt].next=linjie[u]; linjie[u]=cnt++; }
 46 
 47 void init()
 48 {
 49     cin >> w >> y;
 50     memset(linjie, -1, sizeof(linjie));
 51 
 52     int x, y;
 53     while(1)
 54     {
 55         scanf("%d %d", &x, &y);
 56         if (x==-1 && y==-1) break;
 57         addedge(x, y); addedge(y, x);
 58     }
 59 }
 60 
 61 bool dfs(int x)
 62 {
 63     for(int i = linjie[x]; ~i; i=e[i].next)
 64     {
 65         int to = e[i].to;
 66         if (!vis[to]) {
 67             vis[to] = true;
 68             if (match[to]==-1 || dfs(match[to])) {
 69                 match[to] = x;
 70                 match[x] = to;
 71                 return true;
 72             }
 73         }
 74     }
 75     return false;
 76 }
 77 
 78 int work()
 79 {
 80     int ans = 0;
 81     memset(match, -1, sizeof(match));
 82     for ( int i = 1; i <= w; i++ )
 83     {
 84         if (match[i]+1) continue;
 85         memset(vis, 0, sizeof(vis));
 86         if (dfs(i))
 87             ans++;
 88     }
 89     return ans;
 90 }
 91 
 92 int main()
 93 {
 94 
 95     #ifndef ONLINE_JUDGE
 96         freopen("input.txt", "r", stdin);
 97     #endif  
 98 
 99     init();    
100     printf("%d\n", work());
101     
102 
103     return 0;
104 
105 }
View Code

  

  2. 最小路径覆盖(二分图匹配求最小路径覆盖)

  这里是不可交叉最小路径覆盖,最小路径覆盖就是指在一张图中选择条数最少的路径使得所有路径能覆盖全部节点。一条路径中起点入度为0,终点出度为0,因为路径不可交叉,不是起点和终点的点出度入度都为1,那么可以将每一个点拆为两个点xa, xb,这样分成一个二分图,左半边(xa)代表n个点的出度,右半边(xb)代表n个点的入度。那么如果原图中有一条有向边u->v,即左半边的u(出度)到右半边的v(入度)连一条双向边,这样跑一遍二分图最大匹配,左边没匹配到的点就是所有路径的终点(出度为0),右边没匹配到的点是所有路径的起点(入度为0),所以最小路径数目就是n-最大匹配数。

  1 #include <iostream>
  2 #include <string.h>
  3 #include <cstdio>
  4 #include <queue>
  5 #include <stack>
  6 #include <math.h>
  7 #include <string>
  8 #include <algorithm>
  9 
 10 #define SIGMA_SIZE 26
 11 #define pii pair<int,int>
 12 #define lson rt<<1
 13 #define rson rt<<1|1
 14 #define lowbit(x) (x&-x)
 15 #define fode(i, a, b) for(int i=a; i>=b; i--)
 16 #define foe(i, a, b) for(int i=a; i<=b; i++)
 17 #define fod(i, a, b) for(int i=a; i>b; i--)
 18 #define fo(i, a, b) for(int i=a; i<b; i++)
 19 //#pragma warning ( disable : 4996 )
 20 
 21 using namespace std;
 22 typedef long long LL;
 23 inline LL LMax(LL a, LL b) { return a>b ? a : b; }
 24 inline LL LMin(LL a, LL b) { return a>b ? b : a; }
 25 inline LL lgcd(LL a, LL b) { return b == 0 ? a : lgcd(b, a%b); }
 26 inline LL llcm(LL a, LL b) { return a / lgcd(a, b)*b; }  //a*b = gcd*lcm
 27 inline int Max(int a, int b) { return a>b ? a : b; }
 28 inline int Min(int a, int b) { return a>b ? b : a; }
 29 inline int gcd(int a, int b) { return b == 0 ? a : gcd(b, a%b); }
 30 inline int lcm(int a, int b) { return a / gcd(a, b)*b; }  //a*b = gcd*lcm
 31 const LL INF = 0x3f3f3f3f3f3f3f3f;
 32 const LL mod = 1e9+7;
 33 const double eps = 1e-8;
 34 const int inf = 0x3f3f3f3f;
 35 const int maxk = 1e5+5;
 36 const int maxn = 2010;
 37 
 38 struct node {
 39     int to, next;
 40 }e[maxk];
 41 
 42 int n, m, cnt;
 43 int linjie[maxn], mac[maxn];
 44 bool vis[maxn];
 45 
 46 void addedge( int u, int v )
 47 { e[cnt].to = v; e[cnt].next = linjie[u]; linjie[u] = cnt++; }
 48 
 49 void init()
 50 {
 51     cin >> n >> m;
 52     cnt = 0; 
 53     memset(linjie, -1, sizeof(linjie));
 54     
 55     int x, y;
 56     foe(i, 1, m)
 57     {
 58         scanf("%d %d", &x, &y);
 59         addedge(x, y+n); addedge(y+n, x);
 60     }
 61 }
 62 
 63 bool dfs(int x)
 64 {
 65     for ( int i = linjie[x]; ~i; i=e[i].next )
 66     {
 67         int to = e[i].to;
 68         if (!vis[to]) {
 69             vis[to] = true;
 70             if ( mac[to]==-1 || dfs(mac[to]) ) {
 71                 mac[to] = x;
 72                 mac[x] = to;
 73                 return true;
 74             }
 75         }
 76     }
 77     return false;
 78 }
 79 
 80 int work()
 81 {
 82     int ans = 0;
 83     memset(mac, -1, sizeof(mac));
 84     foe(i, 1, n)
 85     {
 86         if (mac[i]+1) continue;
 87         memset(vis, 0, sizeof(vis));
 88         if (dfs(i))
 89             ans++;
 90     }
 91     return ans;
 92 }
 93 
 94 int main()
 95 {
 96 
 97     #ifndef ONLINE_JUDGE
 98         freopen("input.txt", "r", stdin);
 99     #endif
100 
101     init();
102     printf("%d\n", n-work());
103     
104     return 0;
105 }
View Code

   3. 最长不下降子序列问题(最多不相交路径)

  第一问最长上升序列的长度len,用n^2的dp解决,dp[i]表示以第i个数字结尾的子序列最长长度。

  第二问是询问每个数字只可以取一次,最多可以取出多少个长度为len的不下降子序列,可以转化成最长不相交路径问题,选取超级源点s汇点t,将满足条件的点用流量为1的边连起来跑网络流得出的结果就是路径条数。但因为每个数字只能取一次,但是网络流算法是不管一个点能用多少次的,所以我们将一个点x拆为两个点xa, xb,xa->xb连一条流量为1的边。这样假如原图有经过x的边u -> x ->v,就可以变成 u -> xa -> xb -> v,因为xa->xb流量为1,所有即使有多条边经过x,最终也只能有一条路能通过xa->xb。这样就根据前面dp的结果建图就行了

  第三问是说a1和an能用多次的情况下,最多可以取出多少个长度为len的不下降子序列。刚才把点拆成两个是在两点间连一条容量为1的边,则如果在两点间连一条容量无限大的边,就相当于把两点和为一点。所有如果a1可以作为起点,an可以作为终点的时候,把a1和s合成一个点,an和汇点合成一个点,就相当于该点能取无限次了。

  1 #include <iostream>
  2 #include <string.h>
  3 #include <cstdio>
  4 #include <queue>
  5 #include <stack>
  6 #include <math.h>
  7 #include <string>
  8 #include <algorithm>
  9 
 10 #define SIGMA_SIZE 26
 11 #define lson rt<<1
 12 #define rson rt<<1|1
 13 #define lowbit(x) (x&-x)
 14 #define fode(i, a, b) for(int i=a; i>=b; i--)
 15 #define foe(i, a, b) for(int i=a; i<=b; i++)
 16 #define fod(i, a, b) for(int i=a; i>b; i--)
 17 #define fo(i, a, b) for(int i=a; i<b; i++)
 18 //#pragma warning ( disable : 4996 )
 19 
 20 using namespace std;
 21 typedef long long LL;
 22 inline LL LMax(LL a, LL b) { return a>b ? a : b; }
 23 inline LL LMin(LL a, LL b) { return a>b ? b : a; }
 24 inline LL lgcd(LL a, LL b) { return b == 0 ? a : lgcd(b, a%b); }
 25 inline LL llcm(LL a, LL b) { return a / lgcd(a, b)*b; }  //a*b = gcd*lcm
 26 inline int Max(int a, int b) { return a>b ? a : b; }
 27 inline int Min(int a, int b) { return a>b ? b : a; }
 28 inline int gcd(int a, int b) { return b == 0 ? a : gcd(b, a%b); }
 29 inline int lcm(int a, int b) { return a / gcd(a, b)*b; }  //a*b = gcd*lcm
 30 const LL INF = 0x3f3f3f3f3f3f3f3f;
 31 const LL mod = 998244353;
 32 const double eps = 1e-8;
 33 const int inf = 0x3f3f3f3f;
 34 const int maxk = 1e6+5;
 35 const int maxn = 5000+10;
 36 
 37 struct edge{
 38     int to, next, flow;
 39 }e[maxk];
 40 
 41 int n, cnt, maxl, ans;
 42 int num[maxk], linjie[maxk], dis[maxk];
 43 int dp[maxk];   //dp[i]表示第i个数字结尾的最长序列长度
 44 
 45 void addedge( int u, int v, int w )
 46 { e[cnt].to=v; e[cnt].next=linjie[u]; e[cnt].flow=w; linjie[u]=cnt++; }
 47 
 48 void getDp()
 49 {
 50     foe(j, 1, n)
 51     {   
 52         dp[j] = 1;
 53         fo(i, 1, j)
 54             if (num[i] <= num[j] && dp[i]+1>dp[j])
 55                 dp[j] = dp[i]+1;
 56     }
 57 }
 58 
 59 void init()
 60 {
 61     cin >> n;
 62     foe(i, 1, n) scanf("%d", &num[i]);
 63     getDp();
 64     
 65     maxl = -1;
 66     foe(i, 1, n)
 67         maxl = Max(maxl, dp[i]);
 68     printf("%d\n", maxl);
 69 }
 70 
 71 bool bfs(int s, int t)
 72 {
 73     queue<int> q;
 74     int run;
 75     
 76     memset(dis, -1, sizeof(dis));
 77     dis[s] = 0;
 78     q.push(s);
 79     while(!q.empty())
 80     {
 81         run = q.front(); q.pop();
 82         for( int i = linjie[run]; ~i; i=e[i].next )
 83         {
 84             int to = e[i].to, w = e[i].flow;
 85             if ( dis[to] < 0 && w > 0 )
 86             {
 87                 dis[to] = dis[run]+1;
 88                 q.push(to);
 89             }
 90         }
 91     }
 92 
 93     if (dis[t] > 0) return true;
 94     else return false;
 95 }
 96 
 97 int _find(int s, int t, int low)
 98 {
 99     int ff = 0;
100     if (s == t) return low;
101     for ( int i = linjie[s]; ~i; i=e[i].next )
102     {
103         int v = e[i].to, w = e[i].flow;
104         if ( w > 0
105              && dis[v] == dis[s]+1
106              && (ff = _find(v, t, Min(w, low))) )
107         {
108             e[i].flow -= ff;
109             e[i^1].flow += ff;
110             return ff;
111         }
112     }
113     return 0;
114 }
115 
116 int  dinic(int s, int t)
117 {
118     int tans;
119     while(bfs(s, t))
120     {
121         while( tans = _find(s, t, inf))
122             ans += tans;
123     }
124     return ans;
125 }
126 
127 void solve1()
128 {
129     cnt = 0;
130     memset(linjie, -1, sizeof(linjie));
131     foe(i, 1, n) {
132         if ( dp[i] == 1 ) addedge(0, i, 1), addedge(i, 0, 1);
133         if ( dp[i] == maxl ) addedge(i+n, 2*n+1, 1), addedge(2*n+1, i+n, 1);
134         addedge(i, i+n, 1); addedge(i+n, i, 1);
135         foe(j, i+1, n) {
136             if ( dp[j] == dp[i]+1 && num[j] >= num[i] )
137                 addedge(i+n, j, 1), addedge(j, i+n, 1);
138         }
139     }
140 }
141 
142 bool solve2()
143 {
144     bool flag = true;
145     foe(i, 1, n-1) if (num[i]<=num[i+1]) flag = false;
146     if (flag) return true;
147 
148 
149     addedge(0, 1, inf); addedge(1, 0, inf);
150     addedge(1, 1+n, inf); addedge(1+n, 1, inf);
151     if (dp[n] == maxl)
152     {
153         addedge(n+n, 2*n+1, inf); addedge(2*n+1, n+n, inf);
154         addedge(n, n+n, inf); addedge(n+n, n, inf);
155     }
156 
157     return false;   
158 }
159 
160 int main()
161 {
162 
163     #ifndef ONLINE_JUDGE
164         freopen("input.txt", "r", stdin);
165     #endif  
166 
167     init();
168     solve1(); dinic(0, 2*n+1);
169     printf("%d\n", ans);
170 
171     if (solve2())
172         printf("%d\n", n);
173     else
174         dinic(0, 2*n+1), printf("%d\n", ans);
175 
176     return 0;
177 
178 }
View Code

   

  4. 魔术球问题(最小路径覆盖)

  给n个柱子,每次在任意一根柱子最上面按顺序放上一个球,球的编号顺序是1,2,3.....,要求柱子上相邻的球的编号加起来为完全平方数。可以用最小路劲覆盖去枚举,即:按顺序每次加入新的球编号为k,遍历i  < k,如果i,k两球编号加起来为完全平方数,则两球连边(当然首先得把每个球拆成两个点化成二分图连上左部和右部),然后跑最小路径覆盖看有多少条路径ans,如果ans>柱子数目n,说明最少也需要n+1条柱子(路径)才能容纳k个球,所以答案是k-1。

  另外如果每次用匈牙利算法求最大匹配重复计算太多显得很愚蠢,所以用网络流dinic计算二分图最大匹配,因为dinic算法允许加入新边并在原来的残量网络继续增广,这就需要好好理解网络流算法了。至于路径,网络流其实不好记录路径,所幸这题是二分图且各个边容量为1,所以当一条左部连向右部的边容量为0时,代表这条边肯定在路径上(一条边必定被增广了容量才会减少),然后用类似邻接表的方法存储路径就可以了。

  1 #include <iostream>
  2 #include <string.h>
  3 #include <cstdio>
  4 #include <queue>
  5 #include <stack>
  6 #include <math.h>
  7 #include <string>
  8 #include <algorithm>
  9 
 10 #define SIGMA_SIZE 26
 11 #define pii pair<int,int>
 12 #define lson rt<<1
 13 #define rson rt<<1|1
 14 #define lowbit(x) (x&-x)
 15 #define fode(i, a, b) for(int i=a; i>=b; i--)
 16 #define foe(i, a, b) for(int i=a; i<=b; i++)
 17 #define fod(i, a, b) for(int i=a; i>b; i--)
 18 #define fo(i, a, b) for(int i=a; i<b; i++)
 19 //#pragma warning ( disable : 4996 )
 20 
 21 using namespace std;
 22 typedef long long LL;
 23 inline LL LMax(LL a, LL b) { return a>b ? a : b; }
 24 inline LL LMin(LL a, LL b) { return a>b ? b : a; }
 25 inline LL lgcd(LL a, LL b) { return b == 0 ? a : lgcd(b, a%b); }
 26 inline LL llcm(LL a, LL b) { return a / lgcd(a, b)*b; }  //a*b = gcd*lcm
 27 inline int Max(int a, int b) { return a>b ? a : b; }
 28 inline int Min(int a, int b) { return a>b ? b : a; }
 29 inline int gcd(int a, int b) { return b == 0 ? a : gcd(b, a%b); }
 30 inline int lcm(int a, int b) { return a / gcd(a, b)*b; }  //a*b = gcd*lcm
 31 const LL INF = 0x3f3f3f3f3f3f3f3f;
 32 const LL mod = 1e9+7;
 33 const double eps = 1e-8;
 34 const int inf = 0x3f3f3f3f;
 35 const int maxk = 1e5+5;
 36 const int maxm = 2e4+10;
 37 const int maxn = 5010;
 38 
 39 struct node {
 40     int to, next, flow;
 41 }e[maxk];
 42 
 43 int n, cnt, mm = 60;
 44 int linjie[maxn], dis[maxn], to[maxn];
 45 bool is[maxm], vis[maxn];
 46 
 47 void addedge(int u, int v, int f)
 48 { e[cnt].to=v; e[cnt].next=linjie[u]; e[cnt].flow=f; linjie[u]=cnt++; }
 49 
 50 void init()
 51 {
 52     cnt = 0; memset(linjie, -1, sizeof(linjie));
 53     cin >> n;
 54 
 55     for ( int i = 1; i*i < maxm; i++ )
 56         is[i*i] = true;
 57 }
 58 
 59 bool bfs(int s, int t)
 60 {
 61     queue<int> q;
 62     int run;
 63 
 64     memset(dis, -1, sizeof(dis));
 65     dis[s] = 0; q.push(s);
 66     while(!q.empty())
 67     {
 68         run = q.front(); q.pop();
 69 
 70         for ( int i = linjie[run]; ~i; i=e[i].next )
 71         {
 72             int v = e[i].to, w = e[i].flow;
 73             if ( dis[v]<0 && w > 0 )
 74             {
 75                 dis[v] = dis[run]+1;
 76                 q.push(v);
 77             }
 78         }
 79     }
 80     if (dis[t]>0) return true;
 81     else return false;
 82 }
 83 
 84 int dfs(int s, int t, int low)
 85 {
 86     int ff = 0;
 87     if (s==t) return low;
 88     for ( int i = linjie[s]; ~i; i=e[i].next )
 89     {
 90         int v = e[i].to, w = e[i].flow;
 91         if ( w > 0
 92              && dis[v] == dis[s]+1
 93              && (ff = dfs(v, t, Min(w, low))) )
 94         {
 95             e[i].flow -= ff;
 96             e[i^1].flow += ff;
 97             return ff;
 98         }
 99     }
100     return 0;
101 }
102 
103 int dinic(int s, int t)
104 {
105     int sum = 0;
106     int tans;
107     while(bfs(s, t))
108     {
109         while(tans = dfs(s, t, inf))
110             sum += tans;
111     }
112     return sum;
113 }
114 
115 void caculatePath(int x)
116 {
117     memset(to, -1, sizeof(to));
118     memset(vis, 0, sizeof(vis));
119     foe(i, 1, x)
120     {
121         for( int j = linjie[i]; ~j; j=e[j].next )
122         {
123             ///去掉起点
124             if (!to) continue;
125             ///flow为0的边必然在路径中
126             if (!e[j].flow)
127                 { to[i] = e[j].to-2000; break; }
128         }
129     }
130 }
131 
132 int main()
133 {
134 
135     #ifndef ONLINE_JUDGE
136         freopen("input.txt", "r", stdin);
137     #endif
138 
139     int ans = 0;
140     int s = 0, t = 5000, tmp = 0;
141     init();
142     
143     
144     while(1)
145     {
146         if (tmp-ans > n) break;
147 
148         tmp++;
149         addedge(s, tmp, 1); addedge(tmp, s, 1);
150         addedge(tmp+2000, t, 1); addedge(t, tmp+2000, 1);
151         for( int i = 1; i < tmp; i++ )
152         {
153             if (is[i+tmp])
154                 addedge(i, tmp+2000, 1), addedge(tmp+2000, i, 1);
155         }
156 
157         ans += dinic(s, t);
158     }
159 
160     caculatePath(tmp-1);
161 
162     cout << tmp-1 << endl;
163     foe(i, 1, tmp-1)
164     {
165         if (vis[i]) continue;
166 
167         t = i;
168         while(t+1)
169         {
170             vis[t] = true;
171             printf("%d ", t);
172             t = to[t];
173         }
174         printf("\n");
175     } 
176 
177     return 0;
178 }
View Code

 

  5. (插一个)HihoCoder - 1393(二分图多重匹配模板) 

  就是用最大流求二分图流量...另外这题不用前向弧优化得2000+ms,用了可以跑进15ms...tql

  1 #include <iostream>
  2 #include <string.h>
  3 #include <cstdio>
  4 #include <queue>
  5 #include <stack>
  6 #include <math.h>
  7 #include <string>
  8 #include <algorithm>
  9 
 10 #define SIGMA_SIZE 26
 11 #define pii pair<int,int>
 12 #define lson rt<<1
 13 #define rson rt<<1|1
 14 #define lowbit(x) (x&-x)
 15 #define fode(i, a, b) for(int i=a; i>=b; i--)
 16 #define foe(i, a, b) for(int i=a; i<=b; i++)
 17 #define fod(i, a, b) for(int i=a; i>b; i--)
 18 #define fo(i, a, b) for(int i=a; i<b; i++)
 19 //#pragma warning ( disable : 4996 )
 20 
 21 using namespace std;
 22 typedef long long LL;
 23 inline LL LMax(LL a, LL b) { return a>b ? a : b; }
 24 inline LL LMin(LL a, LL b) { return a>b ? b : a; }
 25 inline LL lgcd(LL a, LL b) { return b == 0 ? a : lgcd(b, a%b); }
 26 inline LL llcm(LL a, LL b) { return a / lgcd(a, b)*b; }  //a*b = gcd*lcm
 27 inline int Max(int a, int b) { return a>b ? a : b; }
 28 inline int Min(int a, int b) { return a>b ? b : a; }
 29 inline int gcd(int a, int b) { return b == 0 ? a : gcd(b, a%b); }
 30 inline int lcm(int a, int b) { return a / gcd(a, b)*b; }  //a*b = gcd*lcm
 31 const LL INF = 0x3f3f3f3f3f3f3f3f;
 32 const LL mod = 1e9+7;
 33 const double eps = 1e-8;
 34 const int inf = 0x3f3f3f3f;
 35 const int maxk = 1e5+5;
 36 const int maxm = 5e4+10;
 37 const int maxn = 510;
 38 
 39 struct node {
 40     int to, next, flow;
 41 }e[maxm];
 42 
 43 int s, t, all;
 44 int n, m, cnt, para;
 45 int linjie[maxn], dis[maxn], cur[maxn];
 46 int need[210], a[210], b[210];
 47 
 48 void addedge(int u, int v, int f)
 49 { e[cnt].to=v; e[cnt].next=linjie[u]; e[cnt].flow=f; linjie[u]=cnt++; }
 50 
 51 void init()
 52 {
 53     all = cnt = 0;
 54     memset(linjie, -1, sizeof(linjie));
 55 
 56     cin >> n >> m;
 57     foe(i, 1, m)
 58     {
 59         scanf("%d", &need[i]); all += need[i];
 60         addedge(i+para, t, need[i]); addedge(t, i+para, need[i]);
 61     }
 62 
 63     foe(i, 1, n)
 64     {
 65         scanf("%d %d", &a[i], &b[i]);
 66         addedge(s, i, a[i]); addedge(i, s, a[i]);
 67 
 68         int tmp;
 69         foe(j, 1, b[i])
 70         {
 71             scanf("%d", &tmp);
 72             addedge(i, tmp+para, 1); addedge(tmp+para, i, 1);
 73         }
 74     }
 75 }
 76 
 77 bool bfs()
 78 {
 79     queue<int> q;
 80     memset(dis, -1, sizeof(dis));
 81 
 82     dis[s] = 0; q.push(s);
 83     while(!q.empty())
 84     {
 85         int run = q.front(); q.pop();
 86         for( int i = linjie[run]; ~i; i=e[i].next )
 87         {
 88             int v = e[i].to, w = e[i].flow;
 89             if ( dis[v] < 0 && w > 0 )
 90             {
 91                 dis[v] = dis[run]+1;
 92                 q.push(v);
 93             }
 94         }
 95     }
 96     if (dis[t] > 0) return true;
 97     else return false;
 98 }
 99 
100 int dfs(int x, int low)
101 {
102     int ff = 0;
103     if (x == t) return low;
104     for ( int &i = cur[x]; ~i; i=e[i].next )
105     {
106         int v = e[i].to, w = e[i].flow;
107         if ( w > 0
108              && dis[v] == dis[x]+1 
109              && (ff = dfs(v, Min(w, low))) )
110         {
111             e[i].flow -= ff;
112             e[i^1].flow += ff;
113             return ff;
114         }     
115     }
116     return 0;
117 }
118 
119 int dinic()
120 {
121     int ans = 0; 
122     int tans;
123     while(bfs())
124     {
125         foe(i, 0, maxn)
126             cur[i] = linjie[i];
127         while( tans = dfs(s, inf))
128             ans += tans;
129     }
130     return ans;
131 }
132 
133 int main()
134 {
135 
136     #ifndef ONLINE_JUDGE
137         freopen("input.txt", "r", stdin);
138     #endif
139     
140     para = 200;
141     s = 0; t = 500;
142     int T; cin >> T;
143     while(T--)
144     {
145         init();
146         //int tmp = dinic();
147         if ( all == dinic() )
148             cout << "Yes" << endl;
149         else 
150             cout << "No" << endl;
151     }
152     return 0;
153 }
View Code

   /圆桌问题,这个还要记录一下路径,不过也很简单(这个必须得加前向弧优化才能过,我还以为是数组开小了WA了好多次)

  1 #include <iostream>
  2 #include <string.h>
  3 #include <cstdio>
  4 #include <queue>
  5 #include <stack>
  6 #include <math.h>
  7 #include <string>
  8 #include <algorithm>
  9 
 10 #define SIGMA_SIZE 26
 11 #define pii pair<int,int>
 12 #define lson rt<<1
 13 #define rson rt<<1|1
 14 #define lowbit(x) (x&-x)
 15 #define fode(i, a, b) for(int i=a; i>=b; i--)
 16 #define foe(i, a, b) for(int i=a; i<=b; i++)
 17 #define fod(i, a, b) for(int i=a; i>b; i--)
 18 #define fo(i, a, b) for(int i=a; i<b; i++)
 19 //#pragma warning ( disable : 4996 )
 20 
 21 using namespace std;
 22 typedef long long LL;
 23 inline LL LMax(LL a, LL b) { return a>b ? a : b; }
 24 inline LL LMin(LL a, LL b) { return a>b ? b : a; }
 25 inline LL lgcd(LL a, LL b) { return b == 0 ? a : lgcd(b, a%b); }
 26 inline LL llcm(LL a, LL b) { return a / lgcd(a, b)*b; }  //a*b = gcd*lcm
 27 inline int Max(int a, int b) { return a>b ? a : b; }
 28 inline int Min(int a, int b) { return a>b ? b : a; }
 29 inline int gcd(int a, int b) { return b == 0 ? a : gcd(b, a%b); }
 30 inline int lcm(int a, int b) { return a / gcd(a, b)*b; }  //a*b = gcd*lcm
 31 const LL INF = 0x3f3f3f3f3f3f3f3f;
 32 const LL mod = 1e9+7;
 33 const double eps = 1e-8;
 34 const int inf = 0x3f3f3f3f;
 35 const int maxk = 1e5+5;
 36 const int maxm = 1e6+10;
 37 const int maxn = 5010;
 38 
 39 struct node {
 40     int to, next, flow;
 41 }e[maxm];
 42 
 43 int s, t, para, all;
 44 int m, n, cnt;
 45 int linjie[maxn], dis[maxn], cur[maxn];
 46 vector<int> vec[300];
 47 
 48 void addedge( int u, int v, int w )
 49 { e[cnt].to=v; e[cnt].next=linjie[u]; e[cnt].flow=w; linjie[u]=cnt++; }
 50 
 51 void init()
 52 {
 53     all = cnt = 0; memset(linjie, -1, sizeof(linjie));
 54     s = 0; t = 1000; para = 500;
 55     cin >> m >> n;
 56 
 57     int tmp;
 58     foe(i, 1, m) scanf("%d", &tmp), addedge(s, i, tmp), addedge(i, s, 0), all += tmp;
 59     foe(i, 1, n) scanf("%d", &tmp), addedge(i+para, t, tmp), addedge(t, i+para, 0);
 60     foe(i, 1, m)
 61         foe(j, 1, n)
 62             addedge(i, j+para, 1), addedge(j+para, i, 0);
 63 }
 64 
 65 bool bfs()
 66 {
 67     queue<int> q;
 68     memset(dis, -1, sizeof(dis));
 69 
 70     dis[s] = 0; q.push(s);
 71     while(!q.empty())
 72     {
 73         int u = q.front(); q.pop();
 74         for ( int i = linjie[u]; ~i; i=e[i].next )
 75         {
 76             int v = e[i].to, w = e[i].flow;
 77             if ( dis[v]<0 && w>0 )
 78             {
 79                 dis[v] = dis[u] + 1;
 80                 q.push(v);
 81             }
 82         }
 83     }
 84     
 85     if (dis[t]>0) return true;
 86     else return false;
 87 }
 88 
 89 int dfs(int x, int low)
 90 {
 91     int ff = 0;
 92     if (x == t) return low;
 93 
 94     for ( int &i = cur[x]; ~i; i=e[i].next )
 95     {
 96         int v = e[i].to, w = e[i].flow;
 97         if ( w > 0 
 98              && dis[v] == dis[x] + 1 
 99              && (ff = dfs(v, Min(w, low))) )
100         {
101             e[i].flow -= ff;
102             e[i^1].flow += ff;
103             return ff;
104         } 
105     }
106     return 0;
107 }
108 
109 int dinic()
110 {
111     int ans = 0;
112     int tans;
113     while(bfs())
114     {
115         foe(i, 0, t) cur[i] = linjie[i];
116         while( tans = dfs(s, inf) )
117             ans += tans;
118     }
119     return ans;
120 }
121 
122 void workPath()
123 {
124     foe(i, 1, m)
125     {
126         for( int j = linjie[i]; ~j; j=e[j].next )
127         {
128             int v = e[j].to, w = e[j].flow;
129             if (!v) continue;           ///去掉起点
130             if (!w) vec[i].push_back(v-para);
131         }
132     }
133 }
134 
135 
136 int main()
137 {
138 
139     #ifndef ONLINE_JUDGE
140         freopen("input.txt", "r", stdin);
141     #endif
142     
143     init();
144     //cout << dinic() << endl;
145     if ( all == dinic() ) {       
146         printf("1\n");
147         workPath();
148         foe(i, 1, m)
149         {
150             fo(j, 0, (int)vec[i].size())
151                 printf("%d ", vec[i][j]);
152             printf("\n");
153         }
154     } else {
155         printf("0\n");
156     }
157 
158     return 0;
159 }
View Code

 

  6. HihoCoder - 1378(最小割最大流)

  将一张网络的所有点分成两部分,一半包含源点S设为G1,一半包含汇点T设为G2,我们将这种划分称为网络的割(显然一个网络可能有很多种割)。定义边集{E|(u, v),u,v不同时属于G1或G2}(即连接G1和G2的边)。

因为E中的每条边都有其流量和容量,设F为从G1流向G2的流量,称为割的流量,易知只要将E中的边流量相加求和就行了(如果某条边(u, v)是从G2流到G1则要变成加相反数);设C为从G1流向G2的边容量之和,称为割的容量,这里我们要求边(u,v)必须是从G1指向G2才能将容量相加,所以F可能为负数(所有边都是从G2指向G1时 F = -Σf(u, v)),而C一定为非负数(当所有边都是从G2指向G1时C = 0)。

因为每条边的流量必定小于等于容量,所以很容易知道F  <= C, 并且我们可以证得一个网络中任意一个割的F就等于当前网络的流量(从S流到T的量)。最大流最小割定理就是:一个网络的最大流流量maxflow一定等于某个割的C,又因为割的流量Fi等于网络流量,即maxflow = C = F;直观上来理解,网络流量一定等于某个割的F,而每个割的F又一定小于等于该割的C,所以该网络中所有的割的C中最小的那一个C,就是网络流所能达到的最大流量F,至于证明就不太懂了。

在这里说下怎么把G1分出来,先跑一遍dinic,这样剩下的图就是残余网络了,这个时候从源点开始dfs/bfs,当一条边流量w > 0 的时候,说明这条边流量并没有满,所以这条边两个端点必然都在G1中;如果一条边(u, v)流量w = 0的时候,说明这条路流量满了,即这条路流量等于其容量,说明这条边必定属于边集E,所以此时u在G1中,v在G2中

  1 #include <iostream>
  2 #include <string.h>
  3 #include <cstdio>
  4 #include <queue>
  5 #include <set>
  6 #include <stack>
  7 #include <math.h>
  8 #include <string>
  9 #include <algorithm>
 10 
 11 #define SIGMA_SIZE 26
 12 #define pii pair<int,int>
 13 #define lson rt<<1
 14 #define rson rt<<1|1
 15 #define lowbit(x) (x&-x)
 16 #define fode(i, a, b) for(int i=a; i>=b; i--)
 17 #define foe(i, a, b) for(int i=a; i<=b; i++)
 18 #define fod(i, a, b) for(int i=a; i>b; i--)
 19 #define fo(i, a, b) for(int i=a; i<b; i++)
 20 //#pragma warning ( disable : 4996 )
 21 
 22 using namespace std;
 23 typedef long long LL;
 24 inline LL LMax(LL a, LL b) { return a>b ? a : b; }
 25 inline LL LMin(LL a, LL b) { return a>b ? b : a; }
 26 inline LL lgcd(LL a, LL b) { return b == 0 ? a : lgcd(b, a%b); }
 27 inline LL llcm(LL a, LL b) { return a / lgcd(a, b)*b; }  //a*b = gcd*lcm
 28 inline int Max(int a, int b) { return a>b ? a : b; }
 29 inline int Min(int a, int b) { return a>b ? b : a; }
 30 inline int gcd(int a, int b) { return b == 0 ? a : gcd(b, a%b); }
 31 inline int lcm(int a, int b) { return a / gcd(a, b)*b; }  //a*b = gcd*lcm
 32 const LL INF = 0x3f3f3f3f3f3f3f3f;
 33 const LL mod = 1e9+7;
 34 const double eps = 1e-8;
 35 const int inf = 0x3f3f3f3f;
 36 const int maxk = 1e5+5;
 37 const int maxm = 1e6+10;
 38 const int maxn = 1010;
 39 
 40 struct edge {
 41     int to, next, flow;
 42 }e[maxm];
 43 
 44 int n, m, cnt, siz, g[502][502];
 45 int linjie[maxn], dis[maxn], cur[maxn];
 46 bool vis[maxn], chos[maxn];
 47 
 48 void addedge(int u, int v, int w)
 49 { e[cnt].to=v; e[cnt].next=linjie[u]; e[cnt].flow=w; linjie[u]=cnt++; }
 50 
 51 bool bfs(int s, int t)
 52 {
 53     queue<int> q;
 54     memset(dis, -1, sizeof(dis));
 55 
 56     dis[s] = 0; q.push(s);
 57     while(!q.empty())
 58     {
 59         int run = q.front(); q.pop();
 60         for ( int i = linjie[run]; ~i; i=e[i].next )
 61         {
 62             int v = e[i].to, w = e[i].flow;
 63             if ( dis[v]<0 && w>0 )
 64             {
 65                 dis[v] = dis[run]+1;
 66                 q.push(v);
 67             }
 68         }
 69     }
 70 
 71     if (dis[t]>0) return true;
 72     else return false;
 73 }
 74 
 75 int dfs(int x, int t, int low)
 76 {
 77     int ff = 0;
 78     if ( x==t ) return low;
 79 
 80     for ( int &i = cur[x]; ~i; i=e[i].next )
 81     {
 82         int v = e[i].to, w = e[i].flow;
 83         if ( w > 0
 84              && dis[v] == dis[x]+1
 85              && (ff = dfs(v, t, Min(w, low))) )
 86         {
 87             e[i].flow -= ff;
 88             e[i^1].flow += ff;
 89             return ff;
 90         }
 91     }
 92     return 0;
 93 }
 94 
 95 int dinic(int s, int t)
 96 {
 97     int tans, ans = 0;
 98     while(bfs(s, t))
 99     {
100         foe(i, 1, n) cur[i] = linjie[i];
101         while( tans = dfs(s, t, inf) )
102             ans += tans;
103     }
104     return ans;
105 }
106 
107 void init()
108 {
109     cnt = 0; memset(linjie, -1, sizeof(linjie));
110     cin >> n >> m;
111 
112     int x, y, w;
113     foe(i, 1, m) scanf("%d%d%d", &x, &y, &w), g[x][y] += w;
114     foe(i, 1, n)
115         foe(j, 1, n)
116             if (g[i][j])
117                 addedge(i, j, g[i][j]), addedge(j, i, 0);
118 }
119 
120 void _find(int x)
121 {
122     chos[x] = vis[x] = true;
123     for ( int i = linjie[x]; ~i; i=e[i].next )
124     {
125         int v = e[i].to, w = e[i].flow; 
126         if ( w > 0 ) chos[v] = true;
127         if ( vis[v] || w==0 ) continue;
128         _find(v);
129     }
130 }
131 
132 int main()
133 {
134 
135     #ifndef ONLINE_JUDGE
136         freopen("input.txt", "r", stdin);
137     #endif
138     
139     init();
140     printf("%d ", dinic(1, n));
141     _find(1);
142     
143     int siz = 0;
144     foe(i, 1, n) if (chos[i]) siz++;
145     printf("%d\n", siz);
146     
147     foe(i, 1, n) if (chos[i]) printf("%d ", i);
148     cout << endl;
149     
150     cout << endl;
151     return 0;
152 }
View Code

   7. P2774 (二分图最小点权覆盖/二分图最大点权独立集)

  一个n*m的方格,每个方格一个权值,问相邻的方格不能同时选时可以选择出最大权值,如果将相邻方格之间连一根线就能变成求最大点权独立集,那么要转换成二分图,根据题意可以把方格分为黑白了两种颜色,每个黑方块向它相邻白方块连一根线,然后根据二分图最大点权独立集  =  点权和 - 二分图最小点权覆盖 = 点权和 - 最小割 = 点权和 - 最大流。从源点s向黑方块连线,白方块向汇点t连线,因为我们要求的最小割一定和点权有关,和汇点源点之间边的权值就是方块的权值,相当于把点权变为边权,而方块之间不应该有流量限制(不应作为割的边集),所以它们之间流量为inf。然后跑网络流就行了。

  1 #include <iostream>
  2 #include <string.h>
  3 #include <cstdio>
  4 #include <queue>
  5 #include <stack>
  6 #include <math.h>
  7 #include <string>
  8 #include <algorithm>
  9 
 10 #define SIGMA_SIZE 26
 11 #define lson rt<<1
 12 #define rson rt<<1|1
 13 #define lowbit(x) (x&-x)
 14 #define fode(i, a, b) for(int i=a; i>=b; i--)
 15 #define foe(i, a, b) for(int i=a; i<=b; i++)
 16 #define fod(i, a, b) for(int i=a; i>b; i--)
 17 #define fo(i, a, b) for(int i=a; i<b; i++)
 18 //#pragma warning ( disable : 4996 )
 19 
 20 using namespace std;
 21 typedef long long LL;
 22 inline LL LMax(LL a, LL b) { return a>b ? a : b; }
 23 inline LL LMin(LL a, LL b) { return a>b ? b : a; }
 24 inline LL lgcd(LL a, LL b) { return b == 0 ? a : lgcd(b, a%b); }
 25 inline LL llcm(LL a, LL b) { return a / lgcd(a, b)*b; }  //a*b = gcd*lcm
 26 inline int Max(int a, int b) { return a>b ? a : b; }
 27 inline int Min(int a, int b) { return a>b ? b : a; }
 28 inline int gcd(int a, int b) { return b == 0 ? a : gcd(b, a%b); }
 29 inline int lcm(int a, int b) { return a / gcd(a, b)*b; }  //a*b = gcd*lcm
 30 const LL INF = 0x3f3f3f3f3f3f3f3f;
 31 const LL mod = 1e9+7;
 32 const double eps = 1e-8;
 33 const int inf = 0x3f3f3f3f;
 34 const int maxm = 10100;
 35 const int maxn = 105;
 36 
 37 struct edge{
 38     int to, next, val;
 39 }e[100010];
 40 
 41 int g[maxn][maxn], linjie[maxm];
 42 int all, row, col, cnt, st, ed, dis[maxm];
 43 bool vis[maxn][maxn];
 44 
 45 int getid(int i, int j)
 46 { return (i-1)*col + j; }
 47 
 48 void addedge(int u, int v, int w)
 49 { e[cnt].to=v; e[cnt].next=linjie[u]; e[cnt].val=w; linjie[u]=cnt++; }
 50 
 51 void init()
 52 {
 53     cnt = all = 0;
 54     cin >> row >> col;
 55     foe(i, 1, row) foe(j, 1, col) scanf("%d", &g[i][j]), all += g[i][j];
 56 
 57     vis[1][1] = true;
 58     foe(i, 2, row) vis[i][1] = !vis[i-1][1];
 59     foe(i, 1, row) foe(j, 2, col) vis[i][j] = !vis[i][j-1];
 60 }
 61 
 62 void makeMap()
 63 {
 64     memset(linjie, -1, sizeof(linjie));
 65     foe(i, 1, row)
 66     {
 67         foe(j, 1, col)
 68         { 
 69             if (vis[i][j]) { 
 70                 addedge(st, getid(i,j), g[i][j]), addedge(getid(i,j), st, 0);
 71                 if (i > 1) addedge(getid(i,j), getid(i-1,j), inf), addedge(getid(i-1,j), getid(i,j), 0);
 72                 if (i < row) addedge(getid(i,j), getid(i+1,j), inf), addedge(getid(i+1,j), getid(i,j), 0);
 73                 if (j > 1) addedge(getid(i,j), getid(i,j-1), inf), addedge(getid(i,j-1), getid(i,j), 0);
 74                 if (j < col) addedge(getid(i,j), getid(i,j+1), inf), addedge(getid(i,j+1), getid(i,j), 0);
 75             }
 76             else { 
 77                 addedge(getid(i,j), ed, g[i][j]), addedge(ed, getid(i,j), 0);
 78             }
 79         }
 80     }
 81 }
 82 
 83 bool bfs(int s, int t)
 84 {
 85     queue<int> q; memset(dis, -1, sizeof(dis));
 86     q.push(s); dis[s] = 0;
 87     while(!q.empty())
 88     {
 89         int u = q.front(); q.pop();
 90         for ( int i = linjie[u]; ~i; i=e[i].next )
 91         {
 92             int v = e[i].to, w = e[i].val;
 93             if ( dis[v]<0 && w>0 )
 94             {
 95                 q.push(v);
 96                 dis[v] = dis[u]+1;
 97             }
 98         }
 99     }
100 
101     if (dis[t] > 0) return true;
102     else return false;
103 }
104 
105 int dfs(int s, int t, int low)
106 {
107     int ff = 0;
108     if (s == t) return low;
109 
110     for ( int i = linjie[s]; ~i; i=e[i].next )
111     {
112         int v = e[i].to, w = e[i].val;
113         if ( w>0 
114              && dis[v]==dis[s]+1
115              && (ff = dfs(v, t, Min(low, w))) )
116         {
117             e[i].val -= ff;
118             e[i^1].val += ff;
119             return ff;
120         }
121     }
122     return 0;
123 }
124 
125 int dinic(int s, int t)
126 {
127     int tans, ans = 0;
128     while(bfs(s, t))
129     {
130         while(tans = dfs(s, t, inf))
131             ans += tans;
132     }
133     return ans;
134 }
135 
136 
137 
138 int main()
139 {
140 
141     #ifndef ONLINE_JUDGE
142         freopen("input.txt", "r", stdin);
143     #endif  
144 
145     st = 0, ed = 10005;
146     init();
147     makeMap();
148 
149     cout << all - dinic(st, ed) << endl;
150 }
View Code

   

  8. POJ 2135(费用流)

  费用流其实就是在网络流基础的改进,网络流算法中选择路径增广是dfs寻找增广路,可以说是随机寻找增广路的,但是如果要使费用最小显然不能随便增广,如果我们每次都选择一条费用最小的可增广路,即这条路要满足两个条件:可增广, 费用最小。我们把费用看作两条路之间的距离,那跑一遍最短路就能找到费用最短的路了,但是这条路不一定能增广,所以比平常最短路判断条件要加一个flow > 0 罢了;因为dijkstra不能用于有负权的路(建图的时候反向边的费用自然是负的),而如果最小费用存在肯定是不存在负环的,所以正符合spfa的要求,英雌用spfa找最短路,找到这条最短路并对其路径进行记录,然后选择这条路上流量最小的flow增广即可。

  1 #include <iostream>
  2 #include <string.h>
  3 #include <cstdio>
  4 #include <queue>
  5 #include <stack>
  6 #include <math.h>
  7 #include <string>
  8 #include <algorithm>
  9 
 10 #define SIGMA_SIZE 26
 11 #define lson rt<<1
 12 #define rson rt<<1|1
 13 #define lowbit(x) (x&-x)
 14 #define fode(i, a, b) for(int i=a; i>=b; i--)
 15 #define foe(i, a, b) for(int i=a; i<=b; i++)
 16 #define fod(i, a, b) for(int i=a; i>b; i--)
 17 #define fo(i, a, b) for(int i=a; i<b; i++)
 18 //#pragma warning ( disable : 4996 )
 19 
 20 using namespace std;
 21 typedef long long LL;
 22 inline LL LMax(LL a, LL b) { return a>b ? a : b; }
 23 inline LL LMin(LL a, LL b) { return a>b ? b : a; }
 24 inline LL lgcd(LL a, LL b) { return b == 0 ? a : lgcd(b, a%b); }
 25 inline LL llcm(LL a, LL b) { return a / lgcd(a, b)*b; }  //a*b = gcd*lcm
 26 inline int Max(int a, int b) { return a>b ? a : b; }
 27 inline int Min(int a, int b) { return a>b ? b : a; }
 28 inline int gcd(int a, int b) { return b == 0 ? a : gcd(b, a%b); }
 29 inline int lcm(int a, int b) { return a / gcd(a, b)*b; }  //a*b = gcd*lcm
 30 const LL INF = 0x3f3f3f3f3f3f3f3f;
 31 const LL mod = 1e9+7;
 32 const double eps = 1e-8;
 33 const int inf = 0x3f3f3f3f;
 34 const int maxm = 10100;
 35 const int maxn = 1050;
 36 
 37 struct edge{
 38     int to, next, val, c;
 39 }e[maxm<<2];
 40 
 41 int n, m;
 42 int cnt, st, ed;
 43 int linjie[maxn], pre[maxn], dis[maxn], path[maxn];
 44 
 45 void addedge(int u, int v, int w, int f)
 46 { e[cnt].to=v; e[cnt].next=linjie[u]; e[cnt].c=f; e[cnt].val=w; linjie[u]=cnt++; }
 47 
 48 void init()
 49 {
 50     cnt = 0; memset(linjie, -1, sizeof(linjie));
 51     st = 0; ed = 1010;
 52 
 53     cin >> n >> m;
 54     
 55     int x, y, f;
 56     foe(i, 1, m)
 57     {
 58         scanf("%d %d %d", &x, &y, &f);
 59         addedge(x, y, 1, f), addedge(y, x, 0, -f);
 60         addedge(y, x, 1, f), addedge(x, y, 0, -f);
 61     }
 62     addedge(st, 1, 2, 0), addedge(1, st, 0, 0);
 63     addedge(n, ed, 2, 0), addedge(ed, n, 0, 0);
 64 }
 65 
 66 bool spfa(int s, int t)
 67 {
 68     memset(pre, -1, sizeof(pre));
 69     memset(dis, 0x3f, sizeof(dis));
 70     dis[s] = 0;
 71 
 72     queue<int> q; q.push(s);
 73     while(!q.empty())
 74     {
 75         int u = q.front(); q.pop();
 76 
 77         for ( int i = linjie[u]; ~i; i=e[i].next )
 78         {
 79             int v = e[i].to, w = e[i].val, c = e[i].c;
 80             if ( w>0 && dis[u]+c<dis[v] )
 81             {
 82                 dis[v] = dis[u]+c;
 83                 pre[v] = u; path[v] = i;
 84                 q.push(v);
 85             }
 86         }
 87     }
 88 
 89     if (pre[t] > 0) return true;
 90     else return false;
 91 }
 92 
 93 int mif(int s, int t)
 94 {   
 95     int cost = 0;
 96     while(spfa(s, t))
 97     {
 98         int ff = inf;
 99         for ( int u = t; u != s; u = pre[u] )
100             ff = Min(ff, e[path[u]].val);
101         
102         cost += dis[t] * ff;
103         for ( int u = t; u != s; u = pre[u] )
104         {
105             e[path[u]].val -= ff;
106             e[path[u]^1].val += ff;
107         }
108     }
109 
110     return cost;
111 }
112 
113 int main()
114 {
115 
116     #ifndef ONLINE_JUDGE
117         freopen("input.txt", "r", stdin);
118     #endif  
119 
120     init();
121     cout << mif(st, ed) << endl;
122 }
View Code

 

posted @ 2018-09-08 14:51  LBNOQYX  阅读(231)  评论(0编辑  收藏  举报