HDU 4888 Redraw Beautiful Drawings(最大流+判最大流网络是否唯一)

Problem Description

Alice and Bob are playing together. Alice is crazy about art and she has visited many museums around the world. She has a good memory and she can remember all drawings she has seen.

Today Alice designs a game using these drawings in her memory. First, she matches K+1 colors appears in the picture to K+1 different integers(from 0 to K). After that, she slices the drawing into grids and there are N rows and M columns. Each grid has an integer on it(from 0 to K) representing the color on the corresponding position in the original drawing. Alice wants to share the wonderful drawings with Bob and she tells Bob the size of the drawing, the number of different colors, and the sum of integers on each row and each column. Bob has to redraw the drawing with Alice‘s information. Unfortunately, somtimes, the information Alice offers is wrong because of Alice‘s poor math. And sometimes, Bob can work out multiple different drawings using the information Alice provides. Bob gets confused and he needs your help. You have to tell Bob if Alice‘s information is right and if her information is right you should also tell Bob whether he can get a unique drawing.

Input

The input contains mutiple testcases.

For each testcase, the first line contains three integers N(1 ≤ N ≤ 400) , M(1 ≤ M ≤ 400) and K(1 ≤ K ≤ 40).
N integers are given in the second line representing the sum of N rows.
M integers are given in the third line representing the sum of M columns.

The input is terminated by EOF.

Output

For each testcase, if there is no solution for Bob, output "Impossible" in one line(without the quotation mark); if there is only one solution for Bob, output "Unique" in one line(without the quotation mark) and output an N * M matrix in the following N lines representing Bob‘s unique solution; if there are many ways for Bob to redraw the drawing, output "Not Unique" in one line(without the quotation mark).

题目大意:有一个矩阵,矩阵的数为0~K。给出矩阵每一行每一列的和。若不存在符合条件的矩阵,输出Impossible。若存在但矩阵不唯一,输出Not Unique。否则输出Unique并输出这个矩阵。

思路:网络最大流,另外开一个源点S和汇点T,源点到每行连一条边,容量为每一行的和。每一列到汇点连一条边,容量为每一列的和。每一行到每一列连一条边,容量为K。判断每行的总和和每列的总和是否相等,不等则输出Impossible,若相等,令这个值为sum。若sum不等于最大流,输出Impossible。否则,判断网络流是否唯一,不唯一输出Not Unique,存在则输出Unique,输出矩阵,矩阵mat[i][j]的值对应第 i 行到第 j 列的边的流量。

至于判断网络流是否唯一,可以采取在残量网络中找环的办法(环的大小必须大于2),若存在环,那么环上的边全部加一,得到一个新的残量网络,则最大流网络不唯一。那么问题转换为如何找环,由于环必然有至少一个点在列点上,而残量网络中,汇点对所有的列点都有边,那么可以从汇点开始DFS找环。

DFS判是否存在环可以借鉴tarjan求双连通分量的算法,具体可以看代码(这一步的复杂度为O(V + E)即O(n^2),虽然更粗暴的方法也可以过,但是跑得没那么快。)。

代码(218MS):

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <iostream>
  4 #include <algorithm>
  5 #include <queue>
  6 #include <numeric>
  7 using namespace std;
  8 typedef long long LL;
  9
 10 const int MAXN = 410;
 11 const int MAXV = MAXN << 1;
 12 const int MAXE = 2 * MAXN * MAXN;
 13 const int INF = 0x3f3f3f3f;
 14
 15 struct ISAP {
 16     int head[MAXV], cur[MAXV], gap[MAXV], dis[MAXV], pre[MAXV];
 17     int to[MAXE], next[MAXE], flow[MAXE];
 18     int n, ecnt, st, ed;
 19
 20     void init(int n) {
 21         this->n = n;
 22         memset(head + 1, -1, n * sizeof(int));
 23         ecnt = 0;
 24     }
 25
 26     void add_edge(int u, int v, int c) {
 27         to[ecnt] = v; flow[ecnt] = c; next[ecnt] = head[u]; head[u] = ecnt++;
 28         to[ecnt] = u; flow[ecnt] = 0; next[ecnt] = head[v]; head[v] = ecnt++;
 29     }
 30
 31     void bfs() {
 32         memset(dis + 1, 0x3f, n * sizeof(int));
 33         queue<int> que; que.push(ed);
 34         dis[ed] = 0;
 35         while(!que.empty()) {
 36             int u = que.front(); que.pop();
 37             gap[dis[u]]++;
 38             for(int p = head[u]; ~p; p = next[p]) {
 39                 int v = to[p];
 40                 if(flow[p ^ 1] && dis[u] + 1 < dis[v]) {
 41                     dis[v] = dis[u] + 1;
 42                     que.push(v);
 43                 }
 44             }
 45         }
 46     }
 47
 48     int max_flow(int ss, int tt) {
 49         st = ss, ed = tt;
 50         int ans = 0, minFlow = INF;
 51         for(int i = 0; i <= n; ++i) {
 52             cur[i] = head[i];
 53             gap[i] = 0;
 54         }
 55         bfs();
 56         int u = pre[st] = st;
 57         while(dis[st] < n) {
 58             bool flag = false;
 59             for(int &p = cur[u]; ~p; p = next[p]) {
 60                 int v = to[p];
 61                 if(flow[p] && dis[u] == dis[v] + 1) {
 62                     flag = true;
 63                     minFlow = min(minFlow, flow[p]);
 64                     pre[v] = u;
 65                     u = v;
 66                     if(u == ed) {
 67                         ans += minFlow;
 68                         while(u != st) {
 69                             u = pre[u];
 70                             flow[cur[u]] -= minFlow;
 71                             flow[cur[u] ^ 1] += minFlow;
 72                         }
 73                         minFlow = INF;
 74                     }
 75                     break;
 76                 }
 77             }
 78             if(flag) continue;
 79             int minDis = n - 1;
 80             for(int p = head[u]; ~p; p = next[p]) {
 81                 int &v = to[p];
 82                 if(flow[p] && dis[v] < minDis) {
 83                     minDis = dis[v];
 84                     cur[u] = p;
 85                 }
 86             }
 87             if(--gap[dis[u]] == 0) break;
 88             ++gap[dis[u] = minDis + 1];
 89             u = pre[u];
 90         }
 91         return ans;
 92     }
 93
 94     int stk[MAXV], top;
 95     bool sccno[MAXV], vis[MAXV];
 96
 97     bool dfs(int u, int f, bool flag) {
 98         vis[u] = true;
 99         stk[top++] = u;
100         for(int p = head[u]; ~p; p = next[p]) if(flow[p]) {
101             int v = to[p];
102             if(v == f) continue;
103             if(!vis[v]) {
104                 if(dfs(v, u, flow[p ^ 1])) return true;
105             } else if(!sccno[v]) return true;
106         }
107         if(!flag) {
108             while(true) {
109                 int x = stk[--top];
110                 sccno[x] = true;
111                 if(x == u) break;
112             }
113         }
114         return false;
115     }
116
117     bool acycle() {
118         memset(sccno + 1, 0, n * sizeof(bool));
119         memset(vis + 1, 0, n * sizeof(bool));
120         top = 0;
121         return dfs(ed, 0, 0);
122     }
123 } G;
124
125 int row[MAXN], col[MAXN];
126 int mat[MAXN][MAXN];
127 int n, m, k, ss, tt;
128
129 void solve() {
130     int sumr = accumulate(row + 1, row + n + 1, 0);
131     int sumc = accumulate(col + 1, col + m + 1, 0);
132     if(sumr != sumc) {
133         puts("Impossible");
134         return ;
135     }
136     int res = G.max_flow(ss, tt);
137     if(res != sumc) {
138         puts("Impossible");
139         return ;
140     }
141     if(G.acycle()) {
142         puts("Not Unique");
143     } else {
144         puts("Unique");
145         for(int i = 1; i <= n; ++i) {
146             for(int j = 1; j < m; ++j) printf("%d ", G.flow[mat[i][j]]);
147             printf("%d\n", G.flow[mat[i][m]]);
148         }
149     }
150 }
151
152 int main() {
153     while(scanf("%d%d%d", &n, &m, &k) != EOF) {
154         for(int i = 1; i <= n; ++i) scanf("%d", &row[i]);
155         for(int i = 1; i <= m; ++i) scanf("%d", &col[i]);
156         ss = n + m + 1, tt = n + m + 2;
157         G.init(tt);
158         for(int i = 1; i <= n; ++i) G.add_edge(ss, i, row[i]);
159         for(int i = 1; i <= m; ++i) G.add_edge(n + i, tt, col[i]);
160         for(int i = 1; i <= n; ++i) {
161             for(int j = 1; j <= m; ++j) {
162                 mat[i][j] = G.ecnt ^ 1;
163                 G.add_edge(i, n + j, k);
164             }
165         }
166         solve();
167     }
168 }

HDU 4888 Redraw Beautiful Drawings(最大流+判最大流网络是否唯一),布布扣,bubuko.com

时间: 2024-10-20 16:12:25

HDU 4888 Redraw Beautiful Drawings(最大流+判最大流网络是否唯一)的相关文章

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

HDU 4888 Redraw Beautiful Drawings 网络流 建图

题意: 给定n, m, k 下面n个整数 a[n] 下面m个整数 b[n] 用数字[0,k]构造一个n*m的矩阵 若有唯一解则输出这个矩阵,若有多解输出Not Unique,若无解输出Impossible 思路:网络流,,, n行当成n个点,m列当成m个点 从行-列连一条流量为k的边,然后源点-行连一条a[i]的边, 列-汇点 流量为b[i] 瞎了,该退役了 T^T #include<stdio.h> #include<string.h> #include<iostream&

HDU 4888 Redraw Beautiful Drawings(2014 Multi-University Training Contest 3)

题意:给定n*m个格子,每个格子能填0-k 的整数.然后给出每列之和和每行之和,问有没有解,有的话是不是唯一解,是唯一解输出方案. 思路:网络流,一共 n+m+2个点   源点 到行连流量为 所给的 当前行之和.    每行 连到每一列 一条流量为  k的边,每列到汇点连 列和.如果流量等于总和则有解,反之无解(如果列总和不等于行总和也无解).  判断方案是否唯一 找残留网络是否存在长度大于2的环即可,有环说明不唯一. #include<cstdio> #include<cstring&

HDU 4888 Redraw Beautiful Drawings(网络流求矩阵的解)

论文<为什么很多网络流问题总有整数解>http://diaorui.net/archives/189: 参考:http://www.cnblogs.com/yuiffy/p/3929369.html 题意:n*m的矩阵,给出每行的和以及每列的和,判断这样的矩阵是否存在,若存在,是否唯一:若唯一,输出解: 思路:网络流,最大流+判环.网络流常用于求多项式整数解. #include<cstdio> #include<cstring> #include<algorith

hdu 4888 Redraw Beautiful Drawings(最大流,判环)

http://acm.hdu.edu.cn/showproblem.php?pid=4888 加入一个源点与汇点,建图例如以下: 1. 源点 -> 每一行相应的点,流量限制为该行的和 2. 每一行相应的点 -> 每一列相应的点,流量限制为 K 3. 每一列相应的点 -> 汇点,流量限制为该列的和 求一遍最大流,若最大流与矩阵之和相等,说明有解,否则无解.推断唯一解,是推断残量网络中是否存在一个长度大于2的环.若存在说明有多解,否则有唯一解,解就是每条边行i->列j的流量. #inc

hdu - 4888 - Redraw Beautiful Drawings(最大流)

题意:给一个N行M列的数字矩阵的行和以及列和,每个元素的大小不超过K,问这样的矩阵是否存在,是否唯一,唯一则求出各个元素N(1 ≤ N ≤ 400) , M(1 ≤ M ≤ 400), K(1 ≤ K ≤ 40). 题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4888 -->>建图: 1)超级源S = 0,超级汇T = N + M + 1: 2)S到每个行和各连一条边,容量为该行行和: 3)每个行和到每个列和各连一条边,容量为K: 4)每个列和

hdu 4888 Redraw Beautiful Drawings 最大流

好难好难,将行列当成X和Y,源汇点连接各自的X,Y集,容量为行列的和,相当于从源点流向每一行,然后分配流量给每一列,最后流入汇点,这样执意要推断最后是否满流,就知道有没有解,而解就是每一行流向每一列多少流量. 关键在于怎么推断多解的情况.我想不到啊T_T 题讲解,找到一个长度大于2的环. 想了一想,也就是找到还有剩余流量的环,假设找到了,我就能够把当中一条边的流量转移,由于是一个环,所以它又会达到平衡,不会破坏最大流,可是这样转移后,解就多了一种,所以仅仅要推断是否有一个长度大于2的环就够了.

hdu 4888 Redraw Beautiful Drawings 网络流

题目链接 一个n*m的方格, 里面有<=k的数, 给出每一行所有数的和, 每一列所有数的和, 问你能否还原这个图, 如果能, 是否唯一, 如果唯一, 输出还原后的图. 首先对行列建边, 源点向行建边, 权值为这一行的和, 列向汇点建边, 权值为列和, 每一行向每一列建边, 权值为k, 因为上限是k. 然后跑一遍最大流, 如果最大流和所有行的和以及所有列的和相等, 那么可以还原. 判断是否唯一, 用判环的方式, 对图中每一个点dfs, 如果存在环, 说明原图不唯一. 原图每个格子的值等于k-这个格

hdu 4888 Redraw Beautiful Drawings

题目是一个矩阵,每行每列的数字的和都有一个上限,问是否存在可行方案,并且可行方案是否唯一. 第一问比较简单,行列建图,s到每个行节点容量为该行上限,每个列节点连接到t,容量为该列的上限,求最大流,如果满流则有可行方案.第二问就是判断最大流是否唯一,就是在原图中找一个环(经过一条边后不能马上走反向边),环上的边cap-flow都大于0.如果有这个环,那么不唯一,否则唯一.因为流量为k的两个流量图的差别肯定是一个个的环,否则流量不相同,只要按照这个环进行流量的重新分配就可以找到另一个方案. #inc