P6517
网络流,但是大模拟。
题面有点长,不放了。
首先,题目给出的是一个方格图,而且连边是在相邻四个方向(上下左右)之间。
所以可以对方格图进行黑白染色,这样相同颜色的点之间就不会连边。
先考虑没有人类连边的限制,则直接跑二分图多重匹配即可。
建图方法(其中的点都不是空地):
- 源点向每个黑点连边,容量为当前黑点需要连边数。
- 每个黑点向周围四个点连容量为 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;
}