• 欢迎光临~

P6517

开发技术 开发技术 2022-06-01 次浏览

网络流,但是大模拟。

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;
}
程序员灯塔
转载请注明原文链接:P6517
喜欢 (0)