最大流,最小割(例题收集)

题意:问能否构造一个矩阵,使得矩阵中的每个数字范围是1-20并且满足矩阵每行之和与矩阵每列之和与所给数组相等。

思路:尽管矩阵是20*20 ,但是如果爆搜复杂度依旧爆炸,我们考虑使用网络流解决这个问题,下面重点讲解怎么构图。至于怎么写可以参考紫书,与网上的模板。

建图:先来考虑本题的限制是什么,首先i行与j列 存在着一个关系 即共用元素k[i][j],如果我们把数组A[i]B[j]分别看成节点,那么意味着A[i]可以流向B[j]大小最多为k[i][j]的流量至少为1的流量,注意到,网络流中流量最小为0,所以我们可以先给每个元素减1 同时算出减完后的A’[i]B’[j] 求出这个问题下的k’[i][j] 之后k[i][j]=k[i][j]’+1 即可,我们现在可以给A’[i]连一条通向B’[j]的容量为19的边,同时建立一个原点s ,它与每个A’[i]节点连一条边 容量为A’[i]的值 ,建立一个汇点t ,每个B’[j]连一条通向t的边,容量为 B’[j] 跑一遍最大流,如果汇点t的流量之和为sum(B[j])(j from 1 to m) 那么意味可以构造出来 并且k’[i][j] = A’[i]B’[j]的流量。

  1 //主代码来自刘汝佳
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<queue>
  5 #include<vector>
  6 #include<algorithm>
  7 using namespace std;
  8 
  9 const int maxn = 50 + 5;
 10 const int INF = 1000000000;
 11 
 12 struct Edge {
 13     int from, to, cap, flow;
 14     Edge(int u, int v, int c, int f) :from(u), to(v), cap(c), flow(f) {}
 15 };
 16 
 17 struct EdmondsKarp {
 18     int n, m;
 19     vector<Edge> edges;    // 边数的两倍
 20     vector<int> G[maxn];   // 邻接表,G[i][j]表示结点i的第j条边在e数组中的序号
 21     int a[maxn];           // 当起点到i的可改进量
 22     int p[maxn];           // 最短路树上p的入弧编号
 23 
 24     void init(int n) {
 25         for (int i = 0; i < n; i++) G[i].clear();
 26         edges.clear();
 27     }
 28 
 29     void AddEdge(int from, int to, int cap) {
 30         edges.push_back(Edge(from, to, cap, 0));
 31         edges.push_back(Edge(to, from, 0, 0));
 32         m = edges.size();
 33         G[from].push_back(m - 2);
 34         G[to].push_back(m - 1);
 35     }
 36 
 37     int Maxflow(int s, int t) {
 38         int flow = 0;
 39         for (;;) {
 40             memset(a, 0, sizeof(a));
 41             queue<int> Q;
 42             Q.push(s);
 43             a[s] = INF;
 44             while (!Q.empty()) {
 45                 int x = Q.front(); Q.pop();
 46                 for (int i = 0; i < G[x].size(); i++) {
 47                     Edge& e = edges[G[x][i]];
 48                     if (!a[e.to] && e.cap > e.flow) {
 49                         p[e.to] = G[x][i];
 50                         a[e.to] = min(a[x], e.cap - e.flow);
 51                         Q.push(e.to);
 52                     }
 53                 }
 54                 if (a[t]) break;
 55             }
 56             if (!a[t]) break;
 57             for (int u = t; u != s; u = edges[p[u]].from) {
 58                 edges[p[u]].flow += a[t];
 59                 edges[p[u] ^ 1].flow -= a[t];
 60             }
 61             flow += a[t];
 62         }
 63         return flow;
 64     }
 65 };
 66 
 67 EdmondsKarp g;
 68 int no[maxn][maxn];
 69 int a[maxn], b[maxn], str[maxn][maxn];
 70 
 71 int main() {
 72     int R, C, v, kase = 0;
 73     scanf("%d%d", &R, &C);
 74     g.init(R + C + 2);
 75     for (int i = 1; i <= R; i++) {
 76         scanf("%d", &v);
 77         g.AddEdge(0, i, v - C); // row sum is v - last
 78         a[i] = v;
 79     }
 80     int sum_b = 0;
 81     for (int i = 1; i <= C; i++) {
 82         scanf("%d", &v);
 83         g.AddEdge(R + i, R + C + 1, v - R); // col sum is v - last
 84         b[i] = v;
 85         sum_b += v;
 86     }
 87     for (int i = 1; i <= R; i++)
 88         for (int j = 1; j <= C; j++) {
 89             g.AddEdge(i, R + j, 19);
 90             no[i][j] = g.edges.size() - 2; // no[i][j] is the index of arc for cell(i,j)
 91         }
 92     g.Maxflow(0, R + C + 1);
 93 
 94 
 95     for (int i = 1; i <= R; i++)
 96         for (int j = 1; j <= C; j++)
 97             str[i][j] = g.edges[no[i][j]].flow + 1;
 98     for (int i = 1; i <= R; i++) {
 99         int sum = 0;
100         for (int j = 1; j <= C; j++) {
101             sum += str[i][j];
102             if (str[i][j] < 1 || str[i][j]>20) { printf("No
"); return 0; }
103         }
104         if (sum != a[i]) { printf("No
"); return 0; }
105     }
106     for (int j = 1; j <= C; j++) {
107         int sum = 0;
108         for (int i = 1; i <= R; i++)
109             sum += str[i][j];
110         if (sum != b[j]) { printf("No
"); return 0; }
111     }
112 
113 
114     printf("Yes
");
115     for (int i = 1; i <= R; i++) {
116         for (int j = 1; j <= C; j++)
117             printf("%d ", g.edges[no[i][j]].flow + 1); // we subtracted 1 from every cell
118         printf("
");
119     }
120     return 0;
121 }

POJ3281

题意:

N头牛,F种食物和D种饮料,每头牛都有各自喜欢的食物和饮料,而每种食物或饮料都只能分配给一头牛,最多有几头牛能同时得到喜欢的食物和饮料。

解法:

加入只求食物或饮料,那么二分图最大匹配即可,但现在情况不一样,所以我们就最大流跑一次即可,每条边上的容量为1

 代码如下:

  1 struct Edge {
  2     int from, to, cap, flow;
  3 };
  4 struct Dinic {
  5     int n, m, s, t;
  6     vector<Edge> edges;
  7     vector<int> G[MAXN];
  8     bool vis[MAXN];
  9     int d[MAXN];
 10     int cur[MAXN];
 11     void init() {
 12         for (int i = 0; i < MAXN; i++) G[i].clear();
 13         edges.clear();
 14         memset(d, 0, sizeof(d));
 15     }
 16     void AddEdge(int from, int to, int cap) {
 17         edges.push_back({from, to, cap, 0});
 18         edges.push_back({to, from, 0, 0});
 19         m = edges.size();
 20         G[from].push_back(m - 2);
 21         G[to].push_back(m - 1);
 22     }
 23     bool BFS() {
 24         int x, i;
 25         memset(vis, 0, sizeof(vis));
 26         queue<int> Q;
 27         Q.push(s);
 28         d[s] = 0;
 29         vis[s] = 1;
 30         while (!Q.empty()) {
 31             x = Q.front(), Q.pop();
 32             for (i = 0; i < G[x].size(); i++) {
 33                 Edge &e = edges[G[x][i]];
 34                 if (!vis[e.to] && e.cap > e.flow) {
 35                     vis[e.to] = 1;
 36                     d[e.to] = d[x] + 1;
 37                     Q.push(e.to);
 38                 }
 39             }
 40         }
 41         return vis[t];
 42     }
 43     int DFS(int x, int a) {
 44         if (x == t || a == 0) return a;
 45         int flow = 0, f;
 46         for (int &i = cur[x]; i < G[x].size(); i++) {
 47             Edge &e = edges[G[x][i]];
 48             if (d[x] + 1 == d[e.to] &&
 49                 (f = DFS(e.to, min(a, e.cap - e.flow))) > 0) {
 50                 e.flow += f;
 51                 edges[G[x][i] ^ 1].flow -= f;
 52                 flow += f;
 53                 a -= f;
 54                 if (a == 0) break;
 55             }
 56         }
 57         return flow;
 58     }
 59     int Maxflow(int s, int t) {
 60         this->s = s, this->t = t;
 61         int flow = 0;
 62         while (BFS()) {
 63             memset(cur, 0, sizeof(cur));
 64             flow += DFS(s, INF);
 65         }
 66         return flow;
 67     }
 68 } Men;
 69 
 70 int N, F, D;
 71 int cnt;
 72 vector<int> food[102];
 73 vector<int> drink[102];
 74 map<int, int> fd, cow1, cow2, dk;
 75 
 76 void encode() {
 77     cnt = 0;
 78     REP(i, 1, F) fd[i] = ++cnt;
 79     REP(i, 1, N) cow1[i] = ++cnt;
 80     REP(i, 1, N) cow2[i] = ++cnt;
 81     REP(i, 1, D) dk[i] = ++cnt;
 82     ++cnt;
 83 }
 84 
 85 void solve() {
 86     encode();
 87 
 88     Men.init();
 89     int s = 0, t = cnt;
 90 
 91     // source to food
 92     for (int i = 1; i <= F; i++) {
 93         Men.AddEdge(s, fd[i], 1);
 94     }
 95 
 96     // food to cow1
 97     for (int i = 1; i <= F; i++) {
 98         for (int j = 0; j < food[i].size(); j++) {
 99             Men.AddEdge(fd[i], cow1[food[i][j]], 1);
100         }
101     }
102 
103     // cow1 to cow2
104     for (int i = 1; i <= N; i++) {
105         Men.AddEdge(cow1[i], cow2[i], 1);
106         // cow2 to drink
107         for (int j = 0; j < drink[i].size(); j++) {
108             Men.AddEdge(cow2[i], dk[drink[i][j]], 1);
109         }
110     }
111 
112     // cow2 to target
113     for (int i = 1; i <= D; i++) {
114         Men.AddEdge(dk[i], t, 1);
115     }
116 
117     cout << Men.Maxflow(s, t) << endl;
118 
119     return;
120 }
121 
122 int main() {
123 #ifndef ONLINE_JUDGE
124     freopen("input.txt", "r", stdin);
125 #endif  // !ONLINE_JUDGE
126     N = READ(), F = READ(), D = READ();
127     REP(i, 1, N) {
128         int f = READ(), d = READ();
129         REP(j, 1, f) {
130             int o = READ();
131             food[o].push_back(i);
132         }
133         REP(j, 1, d) {
134             int o = READ();
135             drink[i].push_back(o);
136         }
137     }
138     solve();
139     return 0;
140 }
原文地址:https://www.cnblogs.com/romaLzhih/p/9489827.html