Hdu-4888 Redraw Beautiful Drawings 网络流

题目链接


我们建一个二部图,左边是行,右边是列,建个源点与行建边,容量是该行的和,列与新建的汇点建边,容量是该列的和,最后每行与每列建边,容量为题意中的k。建边如图:



跑一遍最大流,如果最大流等于行的和且等于列的和,那么就是有解的,否则无解。这样我们得到了一组解,行i到列j的流量即为i行j列的大小。之后便是判断是否有多种情况了。基本思路是这样的,我们看下图:


有多解的情况一定可以找到这样的4个位置:AB同行,CD同行,AC同列,BD同列,并且他们符合一下两种情况的其中一种:
1、AD未达到k(可变大),BC不是0(可减小)
2、AD不是0(可减小),BC未达到k(可变大)


#include "stdio.h"
#include "queue"
#include "iostream"
#include "math.h"
#include "algorithm"
using namespace std;
const int maxn = 1005;
const int mod = 1000000007 ;
const int inf = 1<<30;
const double eps = 1e-8;
typedef __int64 LL;
typedef pair<int,int> pii;
int n,m,K,tot,s,e;
int sum[maxn];
int dis[maxn],vis[maxn],mat[maxn][maxn];  
int head[maxn];
struct Node
{
	int v,cap,pos,next;
}node[maxn*maxn];
void addedge( int u,int v,int c )
{
	node[tot].v = v;   node[tot].cap = c;
	node[tot].pos = tot; node[tot].next = head[u];	head[u] = tot ++;

	node[tot].v = u;   node[tot].cap = 0;
	node[tot].pos = tot; node[tot].next = head[v];	head[v] = tot ++;
}
bool Dinic_Bfs( int st,int end )        //BFS分层  
{  
	memset( vis,0,sizeof(vis) );  
	memset( dis,0,sizeof(dis) );  
	queue<int>que;  
	dis[st] = 0; vis[st] = true;  
	que.push(st);  
	while( !que.empty() )  
	{  
		int u = que.front();  que.pop();  
		if( u == end )      //分层到汇点就结束  
			return true;  
		for( int i = head[u]; i != -1; i = node[i].next )  
		{  
			Node &v = node[i];
			if( !vis[v.v] && v.cap )  
			{  
				vis[v.v] = true;  
				dis[v.v] = dis[u] + 1;  
				que.push( v.v );  
			}  
		}  
	}  
	return false;  
}  

int Dinic_Dfs( int st,int maxf,int end )    //沿BFS的分层增广  
{  
	int ans = 0,flow;  
	if( st == end )  
		return maxf;  
	for( int i = head[st]; i != -1; i = node[i].next )  
	{  
		Node &v = node[i];
		if( v.cap && dis[v.v] == dis[st] + 1 ){  
			flow = Dinic_Dfs( v.v,v.cap<maxf?v.cap:maxf,end);    //i点能流走的流量  
			v.cap -= flow;         //增广  
			node[v.pos^1].cap += flow;  
			ans += flow;  
			maxf -= flow;  
			if( !maxf )  
				return ans;  
		}  
	}  
	if( !ans )      //注意没得流的时候要标记为-1  
		dis[st] = -1;  
	return ans;  
}  

int Dinic( int st,int end )  
{  
	int ans = 0;  
	while( Dinic_Bfs(st,end) ){     //分层  
		ans += Dinic_Dfs( st,inf,end );  //增广  
	}  
	return ans;  
}
bool dfs( int x,int pre )
{
	vis[x] = 1;
	for( int i = head[x]; i != -1; i = node[i].next )
	{
		if(  node[i].v != pre && node[i].cap )
		{
			if( vis[node[i].v] || dfs( node[i].v,x ) )	return true;
		}
	}
	vis[x] = 0;
	return false;
}
bool fun()
{
	memset( vis,0,sizeof(vis) );
	for( int i = 1; i <= n; i ++ )
	{
		if( dfs( i,i ) )
			return true;
	}
	return false;
}
void init()
{
	tot = 0;
	memset( head,-1,sizeof(head) );
}
void Printf()
{
	puts("Unique");
	for( int i = 1; i <= n; i ++ )
	{
		for( int j = head[i]; j != -1; j = node[j].next )
		{
			Node &v = node[j];
			if( v.v > n && v.v <= n+m )
				mat[i][v.v-n] = K - v.cap;
		}
	}
	for( int i = 1; i <= n; i ++ )
	{
		for( int j = 1; j <= m; j ++ )
		{
			printf("%d%c",mat[i][j],j != m?' ':'\n');
		}
	}
}
int main()
{
	#ifndef ONLINE_JUDGE     
	freopen("data.txt","r",stdin);     
	//freopen("data1.txt","w",stdout);  
	#endif
	while( scanf("%d%d%d",&n,&m,&K) != EOF )
	{
		init();
		int sum1 = 0,sum2 = 0;
		s = n+m+1;  e = n+m+2;
		for( int i = 1; i <= n; i ++ ){
			scanf("%d",&sum[i]);
			sum1 += sum[i];
		}
		for( int i = n+1; i <= n+m; i ++ ){
			scanf("%d",&sum[i]);
			sum2 += sum[i];
		}
		if( sum1 != sum2 )
		{
			puts("Impossible");
			continue;
		}
		for( int i = 1; i <= n; i ++ )
		{
			addedge( s,i,sum[i] );
			for( int j = n+1; j <= n+m; j ++ )
				addedge( i,j,K );
		}
		for( int i = n+1; i <= n+m; i ++ )
			addedge( i,e,sum[i] );
		int ans = Dinic( s,e );
		if( ans != sum1 )
		{
			puts("Impossible");
		}
		else if( fun() )
			 printf("Not Unique\n");  
		else
		{
			Printf();
		}
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值