hdu 4888 Redraw Beautiful Drawings

Redraw Beautiful Drawings

Time Limit: 3000/1500 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 1213    Accepted Submission(s): 243


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).
 

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
 

官方題解:

第一步,考慮如何求是否有解。使用網絡流求解,每一行和每一列分別對應一個點,加上源點和匯點一共有N+M+2個點。有三類邊:

 

1. 源點 -> 每一行對應的點,流量限制爲該行的和

2. 每一行對應的點 -> 每一列對應的點,流量限制爲 K

3. 每一列對應的點 -> 匯點,流量限制爲該列的和

 

 對上圖做最大流,若源點出發的邊和到達匯點的邊全都滿流,則有解,否則無解。若要求構造方案,則 (i,j) 對應的整數就是 i–>  j 的流量。

   第二步,考慮解是否唯一。顯然,解唯一的充分必要條件是完成最大流後的殘餘網絡沒有長度大於 2 的環。所以,判斷解的唯一性可使用dfs,注意遍歷的時候不可以在走完一條邊後馬上走其反向邊,加此限制檢查是否有環即可判斷解是否唯一。

至此,全題已解決。

按照上面的敲了幾發,都T了,感覺找環寫搓了。後來想了一下,把訪問過的邊標記一下,使每條邊最多走一次就行了。

代碼:

#include<queue>
#include<iostream>
#include<string>
#include<cstring>
#include<vector>
#include<iomanip>
#include<stack>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<map>
#include<list>
using namespace std;
const int INF=1e9;
#define rep(i,n) for(int i=0;i<n;i++)
#define rep1(i,n) for(int i=1;i<=n;i++)
#define ini(a) memset(a,0,sizeof(a))
const double eps=1e-6;
const int maxn = 1040;
//const int INF=1e9;
struct Edge{
	int from,to,cap,flow;
	Edge(int f = 0, int t = 0, int c = 0, int fl = 0):from(f),to(t),cap(c),flow(fl){}
};
int n,m,k;
int S,T;
vector<Edge> edges;
vector<int> G[maxn];
bool vis[maxn];
int d[maxn];
int cur[maxn];
int hash[maxn][maxn];
void init(int n)
{
	edges.clear();
	rep(i,n+3) G[i].clear();
}
int AddEdge(int from,int to,int cap){
	edges.push_back(Edge(from, to, cap, 0)); //返回的是這條的編號
	edges.push_back(Edge(to, from, 0, 0));
	int p = edges.size();
	G[from].push_back(p - 2);
	G[to].push_back(p - 1);
	return p - 2;
}
bool BFS(int s,int t){
	memset(vis,0,sizeof(vis));
	queue<int> q;
	q.push(s);
	d[s] = 0; 
	vis[s] = 1;
	while(!q.empty()){
		int x = q.front(); q.pop();
		for(int i = 0;i<(int)G[x].size();i++){
			Edge &e = edges[G[x][i]];
			if(!vis[e.to] && e.cap > e.flow){
				vis[e.to] = 1; d[e.to] = d[x] + 1;
				q.push(e.to);
			}
		}
	}
	return vis[t];
}
int DFS(int x,int a,int t){
	if(x == t || a == 0) return a;
	int flow = 0,f;
	for(int &i = cur[x];i < (int)G[x].size(); i++){
		Edge& e = edges[G[x][i]];
		if(d[x]+1 == d[e.to] &&(f = DFS(e.to,min(a,e.cap-e.flow),t))>0){
			e.flow += f;
			edges[G[x][i]^1].flow -= f;
			flow += f;
			a -= f;
			if(a == 0) break;
		}
	}
	return flow;
}
int maxflow(int s,int t){ //dinic
	int flow = 0;
	while(BFS(s,t)){
		memset(cur, 0, sizeof(cur));
		flow += DFS(s, INF, t);
	}
	return flow;
}
bool vise[400000]; //邊訪問標記,每條邊只能訪問一次,可以防TLE
bool findcy(int u,int fa)// 找大於2的環
{
	for(int i = 0; i < (int)G[u].size(); i++)
	{
		Edge &e = edges[G[u][i]];
		int v = e.to;
		if(v == fa) continue;
		if(e.flow == e.cap) continue; 
		if(vis[v]) return true;
		if(vise[G[u][i]]) continue;
		vise[G[u][i]] = 1;
		vis[v] = true;
		if(findcy(v,u)) return true;
		vis[v] = false;
	}
	return false;
}
int main() {
#ifndef ONLINE_JUDGE
	freopen("in.txt","r",stdin);
	//	freopen("out.txt","w",stdout);
#endif
	while(~scanf("%d%d%d",&n,&m,&k))
	{
		int sum1 = 0,sum2 = 0, w;
		S = 0,T = n + m + 1;
		init(T);
		rep1(i,n) 
		{
			scanf("%d",&w);
			sum1 += w;
			AddEdge(S, i, w);
		}
		rep1(i,m)
		{
			scanf("%d",&w);
			sum2 += w;
			AddEdge(i+n, T, w);
		}
		rep1(i,n) rep1(j,m)
		{
			hash[i][j] = AddEdge(i, j+n, k);
		}
		if(sum1 != sum2)
		{
			puts("Impossible");
			continue;
		}
		int ans = maxflow(S, T);
		if(ans != sum1)
		{
			puts("Impossible");
			continue;
		}
		ini(vis);
		ini(vise);
		bool f = 0;
		for(int i = 0;i <= T; i++)
		{	
			if(!vis[i])
			{ 			
				vis[i] = true;
				if(findcy(i,-1)) 
				{
					f = 1;
					break;
				}
				vis[i] = false;
			}
		}
		if(f) puts("Not Unique");
		else
		{
			puts("Unique");
			rep1(i,n) rep1(j,m)	printf("%d%c",edges[hash[i][j]].flow,j==m?'\n':' ');
		}
	}
	return 0;
}



發佈了52 篇原創文章 · 獲贊 1 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章