[cqoi2012]交换棋子

时间:2021-07-25 20:54:56
 

2668: [cqoi2012]交换棋子

Time Limit: 3 Sec  Memory Limit: 128 MB
Submit: 1334  Solved: 518
[Submit][Status][Discuss]

Description

有一个nm列的黑白棋盘,你每次可以交换两个相邻格子(相邻是指有公共边或公共顶点)中的棋子,最终达到目标状态。要求第i行第j列的格子只能参与mi,j次交换。

Input

第一行包含两个整数nm(1<=n, m<=20)。以下n行为初始状态,每行为一个包含m个字符的01串,其中0表示黑色棋子,1表示白色棋子。以下n行为目标状态,格式同初始状态。以下n行每行为一个包含m个0~9数字的字符串,表示每个格子参与交换的次数上限。
 

Output

输出仅一行,为最小交换总次数。如果无解,输出-1。

Sample Input

3 3
110
000
001
000
110
100
222
222
222

Sample Output

4

HINT

 

Source

 

[Submit][Status][Discuss]

HOME
Back


 

费用流,建图神建图。。。

照例说建图,看上去貌似毫无头绪,然而实际上还是可做的,首先可以看到有一个步数上限,自然就往网络流那边想,然后求最小交换的步数,应该貌似看上去是求一个最小费用,所以费用流。

首先自然是要拆点,比较特殊的是,这个题一个点拆三个点。。。。我们分别叫他们x,y,z,首先先从源点向所有是一的y点连一条容量为1,免费的边,从y点向汇点也这么连。然后对于这两张图,如果第一张图中有棋子,那么就连v[i][j]/2从x到y,(v[i][j]+1)/2从y到z,如果只是第二张图里有,那么就换换加一。最后把所有能互相影响的点从z到x连无限流0费的边,一遍费用流即可。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#define ll long long
#define inf 500000000
#define re register
#define id ((i-1)*m+j)
using namespace std;
struct po
{
int from,to,dis,nxt,w;
}edge[];
int head[],dep[],n,m,s,t,u,num=-,x,y,l,tot,sum,k,fa[];
int dis[],b[],xb[],flow[];
char map1[][],map2[][],mapn[][],cnt;
int dx[]={,-,-,-,,,,,};
int dy[]={,-,,,,,,-,-};
inline long long read()
{
long long x=,c=;
char ch=' ';
while((ch<''||ch>'')&&ch!='-')ch=getchar();
while(ch=='-')c*=-,ch=getchar();
while(ch>=''&&ch<='')x=x*+ch-'',ch=getchar();
return x*c;
}
inline void add_edge(int from,int to,int w,int dis)
{
edge[++num].nxt=head[from];
edge[num].to=to;
edge[num].w=w;
edge[num].dis=dis;
head[from]=num;
}
inline void add(int from,int to,int w,int dis)
{
add_edge(from,to,w,dis);
add_edge(to,from,,-dis);
}
inline bool spfa()
{
memset(b,,sizeof(b));
for(re int i=;i<=t;i++)
dis[i]=inf;
deque<int> q;
b[t]=;dis[t]=;
q.push_back(t);
while(!q.empty())
{
int u=q.front();
q.pop_front();
b[u]=;
for(re int i=head[u];i!=-;i=edge[i].nxt)
{
int v=edge[i].to;
if(edge[i^].w>&&dis[v]>dis[u]-edge[i].dis)
{
dis[v]=dis[u]-edge[i].dis;
if(!b[v])
{
b[v]=;
if(!q.empty()&&dis[v]>dis[q.front()])
q.push_front(v);
else
q.push_back(v);
}
}
}
}
return dis[s]<inf;
}
inline int dfs(int u,int low)
{
if(u==t)
{
b[t]=;
return low;
}
int diss=;
b[u]=;
for(re int i=head[u];i!=-;i=edge[i].nxt)
{
int v=edge[i].to;
if(!b[v]&&edge[i].w!=&&dis[v]==dis[u]-edge[i].dis)
{
int check=dfs(v,min(low,edge[i].w));
if(check>)
{
tot+=check*edge[i].dis;
low-=check;
diss+=check;
edge[i].w-=check;
edge[i^].w+=check;
if(low==) break;
}
}
}
return diss;
}
inline int max_flow()
{
int ans=;
while(spfa())
{
b[t]=;
while(b[t])
{
memset(b,,sizeof(b));
ans+=dfs(s,inf);
}
}
return ans;
}
int main()
{
memset(head,-,sizeof(head));
n=read();m=read();
s=;t=n*m*+;
int N=n*m;
for(re int i=;i<=n;i++)
for(re int j=;j<=m;j++){
cin>>map1[i][j];
if(map1[i][j]=='') add(s,id+N,,),cnt++;
}
for(re int i=;i<=n;i++)
for(re int j=;j<=m;j++){
cin>>map2[i][j];
if(map2[i][j]=='') add(id+N,t,,);
}
for(re int i=;i<=n;i++)
for(re int j=;j<=m;j++)
cin>>mapn[i][j];
for(re int i=;i<=n;i++)
for(re int j=;j<=m;j++){
if(map1[i][j]==map2[i][j]==''){
add(id,id+N,(mapn[i][j]-'')/,);add(id+N,id+N+N,(mapn[i][j]-'')/,);
}else if(map1[i][j]==''){
add(id,id+N,(mapn[i][j]-'')/,);add(id+N,id+N+N,(mapn[i][j]+-'')/,);
}else if(map2[i][j]==''){
add(id,id+N,(mapn[i][j]+-'')/,);add(id+N,id+N+N,(mapn[i][j]-'')/,);
}else add(id,id+N,(mapn[i][j]-'')/,),add(id+N,id+N+N,(mapn[i][j]-'')/,);
for(re int k=;k<=;k++){
int lx=dx[k]+i; int ly=dy[k]+j;
if(lx>=&&lx<=n&&ly>=&&ly<=m){
add(id+N+N,(lx-)*m+ly,inf,);
}
}
}
sum=max_flow();
if(sum>=cnt) cout<<tot;
else cout<<"-1";
}