HDU3338 (建图原理详解)

很经典的题,但是看到还是没思路,太蠢了.


注意下面的行列指的是连续空白格子组成的行和列(意思是每行可以分出多个行)

注意到每个空白格子上的数字只会贡献给本列上面的数字和本行左边的数字

所以可以考虑把每行每列抽象为一个点

空白格子连向对应行和对应列,流量是 [ 1 , 9 ] [1,9] [1,9]

但是流量最低可以是 0 0 0,所以我们把流量设置为 8 8 8,这样 [ 0 , 8 ] [0,8] [0,8]可以映射 [ 1 , 9 ] [1,9] [1,9]

但这样有个问题,空白格子流向对应行的流量应该等于对应列的流量

所以可以把空白格子放中间这样建图

Ⅰ . 源 点 s 连 向 每 一 行 , 流 量 是 行 和 − 本 行 空 白 格 子 数 \color{Red}Ⅰ.源点s连向每一行,流量是行和-本行空白格子数 .s,

Ⅱ . 每 一 行 向 对 应 的 空 白 格 子 连 边 , 流 量 是 8 \color{Red}Ⅱ.每一行向对应的空白格子连边,流量是8 .,8

Ⅲ . 空 白 格 子 向 对 应 的 列 连 边 , 流 量 是 8 \color{Red}Ⅲ.空白格子向对应的列连边,流量是8 .,8

Ⅳ . 每 列 向 汇 点 t 连 边 , 流 量 是 列 和 − 本 列 空 白 格 子 数 \color{Red}Ⅳ.每列向汇点t连边,流量是列和-本列空白格子数 .t,

其 实 还 可 以 优 化 , 因 为 空 白 格 子 是 不 需 要 的 其实还可以优化,因为空白格子是不需要的 ,

它 只 是 起 连 接 对 应 行 和 对 应 列 的 纽 带 而 已 它只是起连接对应行和对应列的纽带而已

所 以 直 接 行 和 列 连 流 量 8 的 边 即 可 所以直接行和列连流量8的边即可 8

跑 最 大 流 , 满 流 就 是 合 法 解 , 反 向 弧 的 流 量 就 是 对 应 空 白 格 子 填 的 数 字 − 1 跑最大流,满流就是合法解,反向弧的流量就是对应空白格子填的数字-1 ,,1

#include 
using namespace std;
const int maxn=2e5+10;
const int inf=1e9;
struct edge{
	int to,nxt,flow;
}d[maxn]; int head[maxn],cnt=1;
void add(int u,int v,int flow){
	d[++cnt]=(edge){v,head[u],flow},head[u]=cnt;
	d[++cnt]=(edge){u,head[v],0},head[v]=cnt;
}
int n,m,s,t,a[109][109][3],vis[109][109];
int col[maxn],row[maxn],colnum,rownum,dis[maxn];
bool bfs()
{
	for(int i=0;i<=t;i++)	dis[i]=0;
	dis[s]=1;
	queueq; q.push( s );
	while( !q.empty() )
	{
		int u=q.front(); q.pop();
		for(int i=head[u];i;i=d[i].nxt )
		{
			int v=d[i].to;
			if( d[i].flow&&dis[v]==0 )
			{
				dis[v]=dis[u]+1;
				if( v==t )	return true;
				q.push( v );
			}
		}
	}
	return false;
}
int dinic(int u,int flow)
{
	if( u==t )	return flow;
	int res=flow;
	for(int i=head[u];i&&res;i=d[i].nxt )
	{
		int v=d[i].to;
		if( dis[v]==dis[u]+1&&d[i].flow)
		{
			int temp=dinic(v,min(res,d[i].flow) );
			if( temp==0 )	dis[v]=0;
			res-=temp;
			d[i].flow-=temp;
			d[i^1].flow+=temp;
		}
	}
	return flow-res;
}
void init()
{
	for(int i=0;i<=t;i++)	head[i]=0;
	cnt=1;
	memset(vis,0,sizeof(vis));
	memset(a,0,sizeof(a));
}
int get(string w,int l,int r)
{
	if( w[l]=='X' )	return -1;
	int ans=0;
	for(int i=l;i<=r;i++)	ans=ans*10+(w[i]-'0');
	return ans;
}
void build()
{
	init();
	rownum=0,colnum=0;
	for(int i=0;i> str;
		if( str=="......." )
		{
			a[i][j][0]=a[i][j-1][0];//行和
			a[i][j][1]=a[i-1][j][1];//列和 
			int x=a[i][j][0],y=a[i][j][1];
			row[x]--,col[y]--;
			vis[i][j]=1;
			continue;
		}
		int num1= get(str,0,2),num2 = get(str,4,6);
		if( num2!=-1 )	row[++rownum]=num2,a[i][j][0]=rownum;
		if( num1!=-1 )	col[++colnum]=num1,a[i][j][1]=colnum;
	}
	s=0,t=rownum+colnum+1;
	for(int i=1;i<=rownum;i++)	add(s,i,row[i]);
	for(int i=1;i<=colnum;i++)	add(rownum+i,t,col[i]);
	for(int i=0;i> n >> m )
	{
		build();
		while( bfs() )	dinic(s,inf);
		for(int i=0;i

你可能感兴趣的:(网络流经典建模题)