ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

P6517

2022-06-01 13:01:11  阅读:151  来源: 互联网

标签:拆成 连边 容量 int 黑点 P6517


网络流,但是大模拟。

P6517 [CEOI2010 day1] alliances

题面有点长,不放了。

首先,题目给出的是一个方格图,而且连边是在相邻四个方向(上下左右)之间。
所以可以对方格图进行黑白染色,这样相同颜色的点之间就不会连边。

先考虑没有人类连边的限制,则直接跑二分图多重匹配即可。

建图方法(其中的点都不是空地):

  • 源点向每个黑点连边,容量为当前黑点需要连边数。
  • 每个黑点向周围四个点连容量为 1 的边。
  • 每个白点向汇点连边,容量为当前白点所需连边数。

可以想到,人类的连边方法一定是一横一竖。
所以只要把每个表示人类的点拆成两个点,一个点只横向连边,另一个点只竖向连边即可。
拆成的点的连边容量要减半

如果满流说明有解。
输出方案就遍历所有边查看匹配情况。

思路不算特别恶心,但具体实现细节很多,码量也很大。

#include <bits/stdc++.h>
using namespace std;
int rd(){
	int v=1,w=0;char c=getchar();while(c<'0'||c>'9'){if(c=='-')v=-1;c=getchar();}
	while(c>='0'&&c<='9')w=(w<<1)+(w<<3)+(c&15),c=getchar();return w*v;
}void wr(int x){if(x<0)putchar('-'),x=-x;if(x>9)wr(x/10);putchar(x%10+'0');}
const int N=2003,INF=2e9;
int n,m,st,ed,tot,ans,sum;
int a[N][N],f[N][N],bh[N][N][2];
char out[N][N];

int fir[N<<6],cnt=1;
struct E{int v,w,nt;}e[N*10000];
void I(int u,int v,int w){
	e[++cnt]=(E){v,w,fir[u]};fir[u]=cnt;
	e[++cnt]=(E){u,0,fir[v]};fir[v]=cnt;
}void init(){memset(e,0,sizeof(e));cnt=1;memset(fir,0,sizeof(fir));}

int cur[N*1000],d[N*1000];queue <int>q;
bool bfs(){
	memset(d,0,sizeof(d));
	for(int i=0;i<=ed;i++)	cur[i]=fir[i];
	q.push(st);d[st]=1;
	while(q.size()){
		int u=q.front(),V;q.pop();
		for(int i=fir[u];i;i=e[i].nt)
			if(e[i].w&&!d[V=e[i].v])
				q.push(V),d[V]=d[u]+1;
	}return d[ed];
}int dfs(int u,int fl){
	if(u==ed)return fl;int f,V,s=0;
	for(int i=cur[u];i;i=e[i].nt){
		cur[u]=i;
		if(e[i].w&&d[V=e[i].v]==d[u]+1){
			f=dfs(V,min(fl,e[i].w));
			e[i].w-=f;e[i^1].w+=f;
			s+=f;fl-=f;if(!fl)break;
		}
	}if(!s)d[u]=0;return s;
}int dinic(){int ans=0;while(bfs())ans+=dfs(st,INF);return ans;}

int main(){
	n=rd(),m=rd();st=n*m*2+99,ed=n*m*2+100;
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
			a[i][j]=rd();
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
			f[i][j]=(i+j)&1;
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++){
			if(a[i][j])
				bh[i][j][0]=++tot;
			if(a[i][j]==2)
				bh[i][j][1]=++tot;
		}
	
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++){
			if(!a[i][j])continue;
			if(f[i][j]){
				if(a[i][j]==2)
					I(bh[i][j][0],ed,1),I(bh[i][j][1],ed,1);
				else
					I(bh[i][j][0],ed,a[i][j]);
			}else{
				sum+=a[i][j];
				if(a[i][j]==2)
					I(st,bh[i][j][0],1),I(st,bh[i][j][1],1);
				else
					I(st,bh[i][j][0],a[i][j]);
				if(a[i][j]==2){
					if(a[i+1][j])
						I(bh[i][j][0],bh[i+1][j][0],1);
					if(a[i-1][j])
						I(bh[i][j][0],bh[i-1][j][0],1);
					if(a[i][j+1])
						if(a[i][j+1]==2)
							I(bh[i][j][1],bh[i][j+1][1],1);
						else
							I(bh[i][j][1],bh[i][j+1][0],1);
					if(a[i][j-1])
						if(a[i][j-1]==2)
							I(bh[i][j][1],bh[i][j-1][1],1);
						else
							I(bh[i][j][1],bh[i][j-1][0],1);
				}else{
					if(a[i+1][j])
						I(bh[i][j][0],bh[i+1][j][0],1);
					if(a[i-1][j])
						I(bh[i][j][0],bh[i-1][j][0],1);
					if(a[i][j+1])
						if(a[i][j+1]==2)
							I(bh[i][j][0],bh[i][j+1][1],1);
						else
							I(bh[i][j][0],bh[i][j+1][0],1);
					if(a[i][j-1])
						if(a[i][j-1]==2)
							I(bh[i][j][0],bh[i][j-1][1],1);
						else
							I(bh[i][j][0],bh[i][j-1][0],1);
				}
			}
		}
	if(dinic()<sum){
		puts("Impossible!");
		return 0;
	}
	for(int i=1;i<=n*3;i++)
		for(int j=1;j<=m*3;j++)
			out[i][j]='.';
	for(int i=1,x=2;i<=n;i++,x+=3){
		for(int j=1,y=2;j<=m;j++,y+=3){
			if(a[i][j])out[x][y]='O';
			else continue;
			if(f[i][j])continue;
			if(a[i][j]==2){
				for(int k=fir[bh[i][j][0]];k;k=e[k].nt){
					if((e[k].v==bh[i+1][j][1]||e[k].v==bh[i+1][j][0])&&!e[k].w)
						out[x+1][y]='X',out[x+2][y]='X';
					if((e[k].v==bh[i-1][j][1]||e[k].v==bh[i-1][j][0])&&!e[k].w)
						out[x-1][y]='X',out[x-2][y]='X';
				}for(int k=fir[bh[i][j][1]];k;k=e[k].nt){
					if((e[k].v==bh[i][j+1][1]||e[k].v==bh[i][j+1][0])&&!e[k].w)
						out[x][y+1]='X',out[x][y+2]='X';
					if((e[k].v==bh[i][j-1][1]||e[k].v==bh[i][j-1][0])&&!e[k].w)
						out[x][y-1]='X',out[x][y-2]='X';
				}
			}else{
				for(int k=fir[bh[i][j][0]];k;k=e[k].nt){
					if((e[k].v==bh[i+1][j][1]||e[k].v==bh[i+1][j][0])&&!e[k].w)
						out[x+1][y]='X',out[x+2][y]='X';
					if((e[k].v==bh[i-1][j][1]||e[k].v==bh[i-1][j][0])&&!e[k].w)
						out[x-1][y]='X',out[x-2][y]='X';
					if((e[k].v==bh[i][j+1][1]||e[k].v==bh[i][j+1][0])&&!e[k].w)
						out[x][y+1]='X',out[x][y+2]='X';
					if((e[k].v==bh[i][j-1][1]||e[k].v==bh[i][j-1][0])&&!e[k].w)
						out[x][y-1]='X',out[x][y-2]='X';
				}
			}
		}
	}for(int i=1;i<=n*3;i++){
		for(int j=1;j<=m*3;j++)
			putchar(out[i][j]);
		putchar('\n');
	}
	return 0;
}

标签:拆成,连边,容量,int,黑点,P6517
来源: https://www.cnblogs.com/AIskeleton/p/16333922.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有