Redraw Beautiful Drawings
Time Limit: 3000/1500 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
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.
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.
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).
Sample Input
2 2 4
4 2
4 2
4 2 2
2 2 5 0
5 4
1 4 3
9
1 2 3 3
Sample Output
Not Unique
Impossible
Unique
1 2 3 3
Author
Fudan University
Source
2014-07-31 01:22:46 | Accepted | 4888 | 625MS | 5244K | 3493 B | G++ |
题目大意:
求一个矩阵,给出矩阵每行和每列的和,矩阵中数字[0,K]
若矩阵唯一,输出Unique及矩阵
若不唯一,输出Not Unique
若不存在,输出impossible
解题方法:
增加源点汇点,建立网络流,
源点->i行 容量为行和
i行->j列 容量为k
j列->汇点 容量为列和
容易得到,
若最大流<sum,则不存在
否则存在,
接下来转换为判断流是否唯一的问题上,即中间的流是否唯一,即中间的流能否相互转移,从增广路径的思想上来看,只需存在一个环,则可以转换流,故存在多解。问题即判断残余网络上是否存在环。
第一次用了下之前的dinic模板,果然省事许多,可惜判断矩阵是否唯一的dfs写超时了,折腾许久,不过也终究搞定了。
#include <cstdio> #include <cstring> #define N 808 #define M 640008 int d[N],be[N]; int s,t,n,m,k,z,tot,all; bool v[N]; struct Edge{ int x,y,c,next; }e[M*2]; void add(int x, int y, int z)//需保证相反边第一个为偶数 { e[all].x=x; e[all].y=y; e[all].c=z; e[all].next=be[x]; be[x]=all; all++; e[all].x=y; e[all].y=x; e[all].c=0; e[all].next=be[y]; be[y]=all; all++; } bool BFS(int s, int t) { memset(d,-1,sizeof(d)); int head=0,tail=0,q[N]; q[++tail]=s; d[s]=0; while(head<tail){ int cur=q[++head]; for(int i=be[cur]; i!=-1; i=e[i].next) if(e[i].c>0 && d[e[i].y]==-1){ d[e[i].y]=d[cur]+1; q[++tail]=e[i].y; } } return d[t]!=-1; } int Dinic(int s, int t)//防止爆栈 用stack模拟递归 { int ans=0; int stack[N],top; int begin[N]; while(BFS(s,t)) { memcpy(begin,be,sizeof(be)); int cur=s; top=0;//dfs开始 清空栈 while(1) { if(cur==t){ int minc=1000000000,mini; for(int i=0; i<top; i++) if(minc>e[stack[i]].c) { minc=e[stack[i]].c; mini=i;//以便之后回到这继续增广 } for(int i=0; i<top; i++) { e[stack[i]].c-=minc; e[stack[i]^1].c+=minc;//第一个二进制取反 即取相反边 } ans+=minc; top=mini; cur=e[stack[mini]].x; } for(int i=begin[cur]; i!=-1; begin[cur]=i=e[begin[cur]].next) if(e[i].c>0 && d[e[i].y]==d[e[i].x]+1) break; if(begin[cur]!=-1){ stack[top++]=begin[cur]; cur=e[begin[cur]].y; }else{ if(top==0) break; d[cur]=-1;//当前节点不在增广路中 删除 cur=e[stack[--top]].x;//回溯 } } } return ans; } bool dfs(int cur, int fa) { if(v[cur]) return 1; v[cur]=1; for(int i=be[cur]; i!=-1; i=e[i].next) if(e[i].c>0 && e[i].y!=fa && dfs(e[i].y,cur)) return 1; v[cur]=0; return 0; } bool check() { memset(v,0,sizeof(v)); for(int i=1; i<=n; i++) if(dfs(i,-1)) return 1; return 0; } void print() { int ans[N]; for(int i=1; i<=n; i++){ for(int j=be[i]; j!=-1; j=e[j].next) ans[e[j].y]=e[j].c; for(int j=n+1; j<=n+m; j++) if(j!=n+m) printf("%d ",k-ans[j]); else printf("%d ",k-ans[j]); } } int main() { while(scanf("%d%d%d",&n,&m,&k)!=EOF) { s=n+m+1; t=n+m+2; tot=0; all=0; int ans=0; memset(be,-1,sizeof(be)); for(int i=0; i<n; i++){ scanf("%d",&z); add(s,++tot,z); ans+=z; } for(int i=0; i<m; i++){ scanf("%d",&z); add(++tot,t,z); } for(int i=1; i<=n; i++) for(int j=n+1; j<=n+m; j++) add(i,j,k); ans-=Dinic(s,t); if(ans!=0) printf("Impossible "); else { if(check()) printf("Not Unique "); else{ printf("Unique "); print(); } } } return 0; }