HDU 4888 Redraw Beautiful Drawings (2014-多校3-1002,最大流,判最大流有多解)

题目:

http://acm.hdu.edu.cn/showproblem.php?pid=4888

 

题意:

给一个n*m的矩阵的n行之和和m列之和以及限制k,使用0-k的数字填充矩阵使得其行与列之和为给定值

如果不行则输出Impossible

如果有多解则输出Not Unique

如果有一解则输出Unique,并输出构造的矩阵

 

方法:

最大流,判最大流有多解

1、建图:

每一行一个点,每一列一个点

源点与第i个行点连边,权值为第i行之和

第j个列点与汇点连边,权值为第j行之和

第i个行点与第j个列点连边,权值为k

2、跑最大流

3、如果源点与n个行点都流满且m个列点与汇点都流满,则有解,否则无解

4、判最大流有多解:

如果有多解,则某两点流量可以为(f1,f2),(f1-f,f2+f),所以可以根据这个结论判最大流是否有多解:

在残余网络中,如果存在大小大于2的环,则可以出现上述情况,即:有多解

 1 bool dfsc(int u, int fa)
 2 {
 3     vis[u] = 1;
 4     for (int i = head[u]; ~i; i = edge[i].next)
 5     {
 6         int v = edge[i].v;
 7         if (v == fa || edge[i].flow == edge[i].cap) continue;
 8         if (vis[v] || dfsc(v, u)) return 1;
 9     }
10     vis[u] = 0;
11     return 0;
12 }
13 bool check()
14 {
15     memset(vis, 0, sizeof(vis));
16     for (int i = 2; i < N + 2; i++)
17     {
18         if (!vis[i])
19         {
20             vis[i] = 1;
21             if (dfsc(i, i)) return 0;
22             vis[i] = 0;
23         }
24     }
25     return 1;
26 }

5、构造矩阵:

第i个行点与第j个列点的流量即为(i,j)的值

 

代码:

  1 // #pragma comment(linker, "/STACK:102400000,102400000")
  2 #include <cstdio>
  3 #include <iostream>
  4 #include <cstring>
  5 #include <string>
  6 #include <cmath>
  7 #include <set>
  8 #include <list>
  9 #include <map>
 10 #include <iterator>
 11 #include <cstdlib>
 12 #include <vector>
 13 #include <queue>
 14 #include <stack>
 15 #include <algorithm>
 16 #include <functional>
 17 using namespace std;
 18 typedef long long LL;
 19 #define ROUND(x) round(x)
 20 #define FLOOR(x) floor(x)
 21 #define CEIL(x) ceil(x)
 22 // const int maxn = 0;
 23 // const int maxm = 0;
 24 // const int inf = 0x3f3f3f3f;
 25 const LL inf64 = 0x3f3f3f3f3f3f3f3fLL;
 26 const double INF = 1e30;
 27 const double eps = 1e-6;
 28 const int P[4] = {0, 0, -1, 1};
 29 const int Q[4] = {1, -1, 0, 0};
 30 const int PP[8] = { -1, -1, -1, 0, 0, 1, 1, 1};
 31 const int QQ[8] = { -1, 0, 1, -1, 1, -1, 0, 1};
 32 
 33 /**
 34 *最大流最小割:加各种优化的Dinic算法($O(V^2E)$)
 35 *输入:图(链式前向星),n(顶点个数,包含源汇),st(源),ed(汇)
 36 *输出:Dinic(NdFlow)(最大流),MinCut()(最小割)(需先求最大流)
 37 *打印路径方法:按反向边(i&1)的flow 找,或者按边的flow找
 38 */
 39 const int maxn = 810;
 40 const int maxm = 400010;
 41 const int inf = 0x3f3f3f3f;
 42 struct Edge
 43 {
 44     int u, v;
 45     int cap, flow;
 46     int next;
 47 } edge[maxm];
 48 int head[maxn], en; //需初始化
 49 int n, m, d[maxn], cur[maxn];
 50 int st, ed;
 51 bool vis[maxn];
 52 void addse(int u, int v, int cap, int flow)
 53 {
 54     edge[en].u = u;
 55     edge[en].v = v;
 56     edge[en].cap = cap;
 57     edge[en].flow = flow;
 58     edge[en].next = head[u];
 59     head[u] = en++;
 60     cur[u] = head[u];
 61 }
 62 void adde(int u, int v, int cap)
 63 {
 64     addse(u, v, cap, 0);
 65     addse(v, u, 0, 0); //注意加反向0边
 66 }
 67 bool BFS()
 68 {
 69     queue<int> Q;
 70     memset(vis, 0, sizeof(vis));
 71     Q.push(st);
 72     d[st] = 0;
 73     vis[st] = 1;
 74     while (!Q.empty())
 75     {
 76         int u = Q.front();
 77         Q.pop();
 78         for (int i = head[u]; i != -1; i = edge[i].next)
 79         {
 80             int v = edge[i].v;
 81             int w = edge[i].cap - edge[i].flow;
 82             if (w > 0 && !vis[v])
 83             {
 84                 vis[v] = 1;
 85                 Q.push(v);
 86                 d[v] = d[u] + 1;
 87                 if (v == ed) return 1;
 88             }
 89         }
 90     }
 91     return false;
 92 }
 93 int Aug(int u, int a)
 94 {
 95     if (u == ed) return a;
 96     int aug = 0, delta;
 97     for (int &i = cur[u]; i != -1; i = edge[i].next)
 98     {
 99         int v = edge[i].v;
100         int w = edge[i].cap - edge[i].flow;
101         if (w > 0 && d[v] == d[u] + 1)
102         {
103             delta = Aug(v, min(a, w));
104             if (delta)
105             {
106                 edge[i].flow += delta;
107                 edge[i ^ 1].flow -= delta;
108                 aug += delta;
109                 if (!(a -= delta)) break;
110             }
111         }
112     }
113     if (!aug) d[u] = -1;
114     return aug;
115 }
116 int Dinic(int NdFlow)
117 {
118     int flow = 0;
119     while (BFS())
120     {
121         memcpy(cur, head, sizeof(int) * (n + 1));
122         flow += Aug(st, inf);
123         /*如果超过指定流量就return 掉*/
124         if (NdFlow == inf) continue;
125         if (flow > NdFlow) break;
126     }
127     return flow;
128 }
129 /*残余网络*/
130 void Reduce()
131 {
132     for (int i = 0; i < en; i++) edge[i].cap -= edge[i].flow;
133 }
134 /*清空流量*/
135 void ClearFlow()
136 {
137     for (int i = 0; i < en; i++) edge[i].flow = 0;
138 }
139 /*求最小割*/
140 vector<int> MinCut()
141 {
142     BFS();
143     vector<int> ans;
144     for (int u = 0; u < n; u++)
145     {
146         if (!vis[u]) continue;
147         for (int i = head[u]; i != -1; i = edge[i].next)
148         {
149             if (i & 1) continue; /*忽略反向边*/
150             int v = edge[i].v;
151             int w = edge[i].cap;
152             if (!vis[v] && w > 0) ans.push_back(i);
153         }
154     }
155     return ans;
156 }
157 
158 int N, M, K;
159 int a[maxn], b[maxn];
160 int mtx[410][410];
161 void init()
162 {
163     memset(head, -1, sizeof(head));
164     en = 0;
165 }
166 void input()
167 {
168     for (int i = 0; i < N; i++)
169         scanf("%d", &a[i]);
170     for (int i = 0; i < M; i++)
171         scanf("%d", &b[i]);
172 }
173 void debug()
174 {
175     //
176 }
177 void build()
178 {
179     st = 0, ed = 1;
180     n = N + M + 2;
181     for (int i = 0; i < N; i++)
182     {
183         adde(st, i + 2, a[i]);
184     }
185     for (int i = 0; i < M; i++)
186     {
187         adde(i + N + 2, ed, b[i]);
188     }
189     for (int i = 0; i < N; i++)
190     {
191         for (int j = 0; j < M; j++)
192         {
193             adde(i + 2, j + N + 2, K);
194         }
195     }
196 }
197 bool dfsc(int u, int fa)
198 {
199     vis[u] = 1;
200     for (int i = head[u]; ~i; i = edge[i].next)
201     {
202         int v = edge[i].v;
203         if (v == fa || edge[i].flow == edge[i].cap) continue;
204         if (vis[v] || dfsc(v, u)) return 1;
205     }
206     vis[u] = 0;
207     return 0;
208 }
209 bool check()
210 {
211     memset(vis, 0, sizeof(vis));
212     for (int i = 2; i < N + 2; i++)
213     {
214         if (!vis[i])
215         {
216             vis[i] = 1;
217             if (dfsc(i, i)) return 0;
218             vis[i] = 0;
219         }
220     }
221     return 1;
222 }
223 void solve()
224 {
225     build();
226     Dinic(inf);
227     // cout << "flow: " << Dinic(inf) << endl;
228     int flag = 1;
229     for (int i = head[st]; ~i; i = edge[i].next)
230     {
231         if (i & 1) continue;
232         if (edge[i].cap > edge[i].flow)
233         {
234             flag = 0;
235             break;
236         }
237     }
238     for (int i = head[ed]; ~i; i = edge[i].next)
239     {
240         if (i & 0) continue;
241         if (-edge[i].flow < edge[i ^ 1].flow)
242         {
243             flag = 0;
244             break;
245         }
246     }
247     if (!flag)
248     {
249         puts("Impossible");
250         return;
251     }
252     if (!check())
253     {
254         puts("Not Unique");
255         return;
256     }
257     for (int u = 0; u < N; u++)
258     {
259         for (int i = head[u + 2]; ~i; i = edge[i].next)
260         {
261             if (i & 1) continue;
262             int v = edge[i].v - N - 2;
263             mtx[u][v] = edge[i].flow;
264         }
265     }
266     puts("Unique");
267     for (int i = 0; i < N; i++)
268     {
269         for (int j = 0; j < M; j++)
270         {
271             if (j < M - 1) printf("%d ", mtx[i][j]);
272             else printf("%d\n", mtx[i][j]);
273         }
274     }
275 }
276 void output()
277 {
278     //
279 }
280 int main()
281 {
282     // int size = 256 << 20; // 256MB
283     // char *p = (char *)malloc(size) + size;
284     // __asm__("movl %0, %%esp\n" :: "r"(p));
285 
286     // std::ios_base::sync_with_stdio(false);
287 #ifndef ONLINE_JUDGE
288     freopen("in.cpp", "r", stdin);
289 #endif
290 
291     while (~scanf("%d%d%d", &N, &M, &K))
292     {
293         init();
294         input();
295         solve();
296         output();
297     }
298     return 0;
299 }
HDU 4888

 

转载于:https://www.cnblogs.com/xysmlx/p/3878395.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值