Redraw Beautiful Drawings
Time Limit: 3000/1500 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 4410 Accepted Submission(s): 1314
Total Submission(s): 4410 Accepted Submission(s): 1314
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.
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.
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).
2 2 4 4 2 4 2 4 2 2 2 2 5 0 5 4 1 4 3 9 1 2 3 3
Not Unique Impossible Unique 1 2 3 3
Fudan University
2014 Multi-University Training Contest 3
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4888
题目大意:给一个n*m的矩阵的第i行的和,第j列的和(1 <= i <= n, 1 <= j <= m),矩阵中每个元素不超过k,问这样的矩阵是否存在,存在的话是否唯一
题目分析:先把问题转换为网络流模型,从源点向行连边容量为行和,从每个行向每个列连边容量为k,从列向汇点连边容量为列和,判断存在只需要跑最大流,看最大流是否等于矩阵中所有元素的和,这样做其实相当于把n行的每个值通过不超过k的变换变成m列,判断唯一性只需在残余网络中找点数大于2的环即可,由于这个图的特殊性,因为到判断唯一性这步时显然已经有解,即源汇点的弧都满流,剩下的其实是个行到列的二分图,所以实际的环至少包含4个点且是X型的环,这样做的原因是如果存在这样的环,弧的流量就可以通过这个环交换,对样例一画个图就能看出来
第一个图为容量网络,第二个为一种解,明显看出包含一个环,第三个图是第二个图通过流量交换得到的,将弧13的流量变为2,剩下的2通过弧14再通过弧42和弧23到点3。
对于找环,直接DFS即可,这里需要两个标记变量,一个用来找当前的环,另一个用来标记肯定不在环中的点,如果一次DFS没找到环,那这次DFS过的点肯定不在环上,下次就不需要从这些点搜起了。
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4888
题目大意:给一个n*m的矩阵的第i行的和,第j列的和(1 <= i <= n, 1 <= j <= m),矩阵中每个元素不超过k,问这样的矩阵是否存在,存在的话是否唯一
题目分析:先把问题转换为网络流模型,从源点向行连边容量为行和,从每个行向每个列连边容量为k,从列向汇点连边容量为列和,判断存在只需要跑最大流,看最大流是否等于矩阵中所有元素的和,这样做其实相当于把n行的每个值通过不超过k的变换变成m列,判断唯一性只需在残余网络中找点数大于2的环即可,由于这个图的特殊性,因为到判断唯一性这步时显然已经有解,即源汇点的弧都满流,剩下的其实是个行到列的二分图,所以实际的环至少包含4个点且是X型的环,这样做的原因是如果存在这样的环,弧的流量就可以通过这个环交换,对样例一画个图就能看出来
第一个图为容量网络,第二个为一种解,明显看出包含一个环,第三个图是第二个图通过流量交换得到的,将弧13的流量变为2,剩下的2通过弧14再通过弧42和弧23到点3。
对于找环,直接DFS即可,这里需要两个标记变量,一个用来找当前的环,另一个用来标记肯定不在环中的点,如果一次DFS没找到环,那这次DFS过的点肯定不在环上,下次就不需要从这些点搜起了。
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
int const INF = 0x3fffffff;
int n, m, k;
int src, sk, sum, num;
int cnt, head[1005];
int d[1005], ans[505][505];
bool vis[1005], mark[1005];
struct EDGE
{
int to, nxt, cap;
}e[505 * 505 * 2];
void Init()
{
cnt = 0;
sum = 0;
src = 0;
sk = n + m + 1;
memset(head, -1, sizeof(head));
}
void Add(int u, int v, int cap)
{
e[cnt].to = v;
e[cnt].cap = cap;
e[cnt].nxt = head[u];
head[u] = cnt ++;
e[cnt].to = u;
e[cnt].cap = 0;
e[cnt].nxt = head[v];
head[v] = cnt ++;
}
bool BFS()
{
memset(d, -1, sizeof(d));
queue <int> q;
q.push(src);
d[src] = 0;
while(!q.empty())
{
int u = q.front();
q.pop();
for(int i = head[u]; i != -1; i = e[i].nxt)
{
int v = e[i].to;
if(e[i].cap && d[v] == -1)
{
d[v] = d[u] + 1;
q.push(v);
}
}
}
return d[sk] != -1;
}
int DFS(int u, int flow)
{
if(u == sk || flow == 0)
return flow;
int res = 0;
for(int i = head[u]; i != -1; i = e[i].nxt)
{
int v = e[i].to;
if(e[i].cap && d[v] == d[u] + 1)
{
int mi = DFS(v, min(flow, e[i].cap));
e[i].cap -= mi;
e[i ^ 1].cap += mi;
flow -= mi;
res += mi;
if(flow == 0)
return res;
}
}
if(!res)
d[u] = -1;
return res;
}
int Dinic()
{
int ans = 0;
while(BFS())
ans += DFS(src, INF);
return ans;
}
bool Judge(int u, int fa)
{
mark[u] = true;
for(int i = head[u]; i != -1; i = e[i].nxt)
{
int v = e[i].to;
if(e[i].cap && v != fa)
{
if(vis[v])
return true;
vis[v] = true;
if(Judge(v, u))
return true;
vis[v] = false;
}
}
return false;
}
int main()
{
while(scanf("%d %d %d", &n, &m, &k) != EOF)
{
Init();
for(int i = 1; i <= n; i++)
{
scanf("%d", &num);
Add(src, i, num);
sum += num;
for(int j = n + 1; j <= n + m; j++)
Add(i, j, k);
}
for(int i = n + 1; i <= n + m; i++)
{
scanf("%d", &num);
Add(i, sk, num);
}
int maxflow = Dinic();
if(maxflow != sum)
printf("Impossible\n");
else
{
bool flag = true;
memset(vis, false, sizeof(vis));
memset(mark, false, sizeof(mark));
for(int i = 1; i <= n && flag; i++)
{
if(!mark[i])
{
vis[i] = true;
if(Judge(i, -1))
flag = false;
vis[i] = false;
}
}
if(flag)
{
printf("Unique\n");
memset(ans, 0, sizeof(ans));
for(int i = 1; i <= n; i++)
{
for(int j = head[i]; j != -1; j = e[j].nxt)
{
int v = e[j].to;
if(v > n && v <= n + m && (k - e[j].cap))
ans[i][v - n] = k - e[j].cap;
}
}
for(int i = 1; i <= n; i++)
for(int j = 1; j <= m; j++)
printf("%d%c", ans[i][j], j == m ? '\n' : ' ');
}
else
printf("Not Unique\n");
}
}
}