zoukankan      html  css  js  c++  java
  • 【BZOJ2668】[cqoi2012]交换棋子 费用流

    【BZOJ2668】[cqoi2012]交换棋子

    Description

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

    Input

    第一行包含两个整数nm(1<=nm<=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

    题解:容易想到费用流,从S向原图中所有1连边,新图中所有1向T连边,中间边的费用是1。但是中间的边我们既要限制入度又要限制出度,该怎么连呢?

    我们仔细观察发现,如果相邻的两个都是1或都是0肯定不会交换,也就是说我们每次交换都会导致当前点的颜色改变。即如果当前点原图是0新图是0或原图是1新图是1,则该点的入度=出度;如果原图是1新图是0,则入度+1=出度;原图是0新图是1,则入度=出度+1。这样的话解个方程就知道具体的入度和出度限制了,所以我们只需要限制一下入度即可。

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <queue>
    using namespace std;
    queue<int> q;
    int n,m,ta,tb,S,T,cnt,ans;
    char s1[30][30],s2[30][30],s3[30][30];
    inline int _(int a,int b) {return (a-1)*m+b;}
    inline int __(int a,int b) {return (a-1)*m+b+n*m;}
    int to[400010],next[400010],head[1010],cost[400010],flow[400010],dis[1010],pe[1010],pv[1010],inq[1010];
    inline void add(int a,int b,int c,int d)
    {
    	to[cnt]=b,cost[cnt]=c,flow[cnt]=d,next[cnt]=head[a],head[a]=cnt++;
    	to[cnt]=a,cost[cnt]=-c,flow[cnt]=0,next[cnt]=head[b],head[b]=cnt++;
    }
    inline int bfs()
    {
    	memset(dis,0x3f,sizeof(dis));
    	dis[S]=0,q.push(S);
    	int i,u;
    	while(!q.empty())
    	{
    		u=q.front(),q.pop(),inq[u]=0;
    		for(i=head[u];i!=-1;i=next[i])	if(flow[i]&&dis[to[i]]>dis[u]+cost[i])
    		{
    			dis[to[i]]=dis[u]+cost[i],pe[to[i]]=i,pv[to[i]]=u;
    			if(!inq[to[i]])	inq[to[i]]=1,q.push(to[i]);
    		}
    	}
    	return dis[T]<0x3f3f3f3f;
    }
    int main()
    {
    	memset(head,-1,sizeof(head));
    	scanf("%d%d",&n,&m),S=0,T=2*n*m+1;
    	int i,j,a,b;
    	for(i=1;i<=n;i++)
    	{
    		scanf("%s",s1[i]+1);
    		for(j=1;j<=m;j++)	if(s1[i][j]=='1')	ta++,add(S,_(i,j),0,1);
    	}
    	for(i=1;i<=n;i++)
    	{
    		scanf("%s",s2[i]+1);
    		for(j=1;j<=m;j++)	if(s2[i][j]=='1')	tb++,add(_(i,j),T,0,1);
    	}
    	if(ta!=tb)
    	{
    		puts("-1");
    		return 0;
    	}
    	for(i=1;i<=n;i++)
    	{
    		scanf("%s",s3[i]+1);
    		for(j=1;j<=m;j++)
    		{
    			if(s3[i][j]-'0'-s1[i][j]+s2[i][j]<0)
    			{
    				puts("-1");
    				return 0;
    			}
    			add(__(i,j),_(i,j),1,(s3[i][j]-'0'-s1[i][j]+s2[i][j])>>1);
    			for(a=i-1;a<=i+1;a++)	for(b=j-1;b<=j+1;b++)	if((a!=i||b!=j)&&a&&b&&a<=n&&b<=m)
    				add(_(i,j),__(a,b),0,1<<30);
    		}
    	}
    	while(bfs())
    	{
    		ta--,ans+=dis[T];
    		for(i=T;i!=S;i=pv[i])	flow[pe[i]]--,flow[pe[i]^1]++;
    	}
    	printf("%d",ta?-1:ans);
    	return 0;
    }//1 3 100 001 121
  • 相关阅读:
    sublime text 安装json插件
    通过坐标系求覆盖物面积
    关于大数据入门的相关闲聊
    渡月橋 ~君 想ふ~
    数据库快照
    oracle 11g安装与使用
    IaaS、PaaS、SaaS介绍(非原创)
    Android项目模块化/组件化开发(非原创)
    开发人员必备的网络知识(非原创)
    公司常见管理系统介绍(非原创)
  • 原文地址:https://www.cnblogs.com/CQzhangyu/p/7965553.html
Copyright © 2011-2022 走看看