交换棋子

Posted chdy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了交换棋子相关的知识,希望对你有一定的参考价值。

  现在除了上下界网络流 和 最小割模型(最大权闭合子图)一类的正确性不会证明 也不是很会用。剩下的比较熟练了。

这几道 都是我精选的好题 觉得 想了很久都没有结果看题解的题目。

技术图片

题目要求我们 四周相邻的棋子可以交换 但是也同时是在限制次数 最终交换到一个最终状态 。

1. 两个状态 如果黑色棋子和白色棋子个数 不对照的话一定是-1

2. 这道题求最小的次数我们不难想到二分 但是 这个二分没什么用 它跟我们的流量没有任何关系 只跟答案有关 答案跟我们的过程显然联系不大 这个思路弃掉。

3. 那么能够求最小费用 显然就是费用流了 我们把一次交换 想成1费用 最后最小费用最大流就是答案。

4. 此时注意 并非是棋子进行交换而是格子参与交换的次数 是有限制的。

5. 两个棋子进行交换显然我们只需要追究交换出去的那个棋子去了哪里而不是被交换出去的棋子去了哪我们并不关心。这个就是重点了,必须想到这个东西 对于一个从源点出发的流 我们只在意其将要去哪而被交换的东西我们直接忽略。

因为考虑到被交换的棋子一定是不同色的 如果同色那么这个交换将毫无意义不是么也增加了答案的次数所以 被交换的一定是没有用的棋子。

6. 我们不知道是交换进来了还是交换出去了 如果只把一个点拆成两个点的话 我们无法分辨这种情况。

7. 拆成三个点因为一个 从源点 过来的是不占流的 一个 交换进来一个交换出去。

8. 分流问题 如果是入点且不是出点 出去的次数一定比进来的次数多1 出点 不是入点 进来的次数比出去的次数多1 出点和入点都有 平分吧 什么都不是 平分吧。

9 连上费用跑费用流即可。

大体上就是这样 但是一个正确的代码一直不过 70分 略微修改后可过我也不知道为什么 留坑吧 石神帮我看了2h 真是谢谢他了。

技术图片
//#include<bits/stdc++.h>
#include<iomanip>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<queue>
#include<deque>
#include<cmath>
#include<ctime>
#include<cstdlib>
#include<stack>
#include<algorithm>
#include<vector>
#include<cctype>
#include<utility>
#include<set>
#include<bitset>
#include<map>
#define INF 1000000000
#define ll long long
#define min(x,y) (x>y?y:x)
#define max(x,y) (x>y?x:y)
#define RI register ll
#define up(p,i,n) for(ll i=p;i<=n;++i)
#define db double
using namespace std;
char buf[1<<15],*fs,*ft;
inline char getc()

    return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;

inline int read()

    int x=0,f=1;char ch=getchar();
    while(ch<0||ch>9)if(ch==-)f=-1;ch=getchar();
    while(ch>=0&&ch<=9)x=x*10+ch-0;ch=getchar();
    return x*f;

const int MAXN=25,maxn=MAXN*MAXN*MAXN*MAXN;
int n,m,S,T,cnt,sum,sum1,flag,len=1,t,h,maxflow,ans;
char c[MAXN][MAXN];
int a[MAXN][MAXN],pos[MAXN][MAXN],b[MAXN][MAXN];
int lin[maxn],nex[maxn],ver[maxn],e[maxn],e1[maxn];
int pre[maxn],in[maxn],vis[maxn],q[maxn],dis[maxn];
const int dx[9]=0,1,1,1,0,0,-1,-1,-1;
const int dy[9]=0,0,-1,1,1,-1,0,-1,1;
inline void add(int x,int y,int z,int z1)

    ver[++len]=y;nex[len]=lin[x];lin[x]=len;e[len]=z;e1[len]=z1;
    ver[++len]=x;nex[len]=lin[y];lin[y]=len;e[len]=0;e1[len]=-z1;

inline int spfa()

    for(int i=1;i<=T;++i)dis[i]=INF;
    t=h=0;q[++t]=S;vis[S]=1;dis[S]=0;in[S]=INF;
    while(h++<t)
    
        int x=q[h];vis[x]=0;
        for(int i=lin[x];i;i=nex[i])
        
            int tn=ver[i];
            if(!e[i])continue;
            if(dis[tn]>dis[x]+e1[i])
            
                dis[tn]=dis[x]+e1[i];
                in[tn]=min(in[x],e[i]);
                pre[tn]=i;
                if(!vis[tn])q[++t]=tn,vis[tn]=1;
            
        
    
    return dis[T]!=INF;

inline void EK()

    while(spfa())
    
        maxflow+=in[T];
        ans+=in[T]*dis[T];
        int x=T,i=pre[x];
        while(x!=S)
        
            e[i^1]+=in[T];
            e[i]-=in[T];
            x=ver[i^1];i=pre[x];
        
    

int main()

    //freopen("1.in","r",stdin);
    n=read();m=read();S=n*m*3+1;T=S+1;
    for(int i=1;i<=n;++i)scanf("%s",c[i]+1);
    for(int i=1;i<=n;++i)
        for(int j=1;j<=m;++j)
        
            pos[i][j]=++cnt;
            if(c[i][j]==1)++sum,add(S,pos[i][j],1,0),b[i][j]=1;
        
    for(int i=1;i<=n;++i)scanf("%s",c[i]+1);
    for(int i=1;i<=n;++i)
        for(int j=1;j<=m;++j)
            if(c[i][j]==1)++sum1,add(pos[i][j],T,1,0),a[i][j]=1;
    if(sum!=sum1)printf("%d\\n",-1);return 0;
    for(int i=1;i<=n;++i)scanf("%s",c[i]+1);
    for(int i=1;i<=n;++i)
        for(int j=1;j<=m;++j)
        
            int w=(int)(c[i][j]-0);
            for(int k=1;k<=8;++k)
            
                int xx=i+dx[k];
                int yy=j+dy[k];
                if(!pos[xx][yy])continue;
                add(pos[i][j]+n*m*2,pos[xx][yy]+n*m,INF,1);
            
            if((!(a[i][j]^b[i][j]))||(!(w&1)))
            
                add(pos[i][j]+n*m,pos[i][j],(w>>1),0);
                add(pos[i][j],pos[i][j]+n*m*2,(w>>1),0);
            
            else
            
                add(pos[i][j]+n*m,pos[i][j],(w>>1)+a[i][j]?1:0,0);
                add(pos[i][j],pos[i][j]+n*m*2,(w>>1)+b[i][j]?1:0,0);
            
        
    EK();
    if(maxflow!=sum)printf("%d\\n",-1);
    else printf("%d\\n",ans);
    return 0;
70
//#include<bits/stdc++.h>
#include<iomanip>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<queue>
#include<deque>
#include<cmath>
#include<ctime>
#include<cstdlib>
#include<stack>
#include<algorithm>
#include<vector>
#include<cctype>
#include<utility>
#include<set>
#include<bitset>
#include<map>
#define INF 1000000000
#define ll long long
#define min(x,y) (x>y?y:x)
#define max(x,y) (x>y?x:y)
#define RI register ll
#define up(p,i,n) for(ll i=p;i<=n;++i)
#define db double
using namespace std;
char buf[1<<15],*fs,*ft;
inline char getc()

    return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;

inline int read()

    int x=0,f=1;char ch=getchar();
    while(ch<0||ch>9)if(ch==-)f=-1;ch=getchar();
    while(ch>=0&&ch<=9)x=x*10+ch-0;ch=getchar();
    return x*f;

const int MAXN=25,maxn=MAXN*MAXN*24;
int n,m,S,T,cnt,sum,sum1,flag,len=1,t,h,maxflow,ans;
char c[MAXN][MAXN];
int a[MAXN][MAXN],pos[MAXN][MAXN],b[MAXN][MAXN];
int lin[maxn],nex[maxn],ver[maxn],e[maxn],e1[maxn];
int pre[maxn],in[maxn],vis[maxn],q[maxn],dis[maxn];
const int dx[9]=0,1,1,1,0,0,-1,-1,-1;
const int dy[9]=0,0,-1,1,1,-1,0,-1,1;
inline void add(int x,int y,int z,int z1)

    ver[++len]=y;nex[len]=lin[x];lin[x]=len;e[len]=z;e1[len]=z1;
    ver[++len]=x;nex[len]=lin[y];lin[y]=len;e[len]=0;e1[len]=-z1;

inline int spfa()

    for(int i=1;i<=T;++i)dis[i]=INF;
    t=h=0;q[++t]=S;vis[S]=1;dis[S]=0;in[S]=INF;
    while(h++<t)
    
        int x=q[h];vis[x]=0;
        for(int i=lin[x];i;i=nex[i])
        
            int tn=ver[i];
            if(!e[i])continue;
            if(dis[tn]>dis[x]+e1[i])
            
                dis[tn]=dis[x]+e1[i];
                in[tn]=min(in[x],e[i]);
                pre[tn]=i;
                if(!vis[tn])q[++t]=tn,vis[tn]=1;
            
        
    
    return dis[T]!=INF;

inline void EK()

    while(spfa())
    
        maxflow+=in[T];
        ans+=in[T]*dis[T];
        int x=T,i=pre[x];
        while(x!=S)
        
            e[i^1]+=in[T];
            e[i]-=in[T];
            x=ver[i^1];i=pre[x];
        
    

int main()

    //freopen("1.in","r",stdin);
    n=read();m=read();S=n*m*3+1;T=S+1;
    for(int i=1;i<=n;++i)scanf("%s",c[i]+1);
    for(int i=1;i<=n;++i)
        for(int j=1;j<=m;++j)
        
            pos[i][j]=++cnt;
            if(c[i][j]==1)++sum,add(S,pos[i][j],1,0),b[i][j]=1;
        
    for(int i=1;i<=n;++i)scanf("%s",c[i]+1);
    for(int i=1;i<=n;++i)
        for(int j=1;j<=m;++j)
            if(c[i][j]==1)++sum1,add(pos[i][j],T,1,0),a[i][j]=1;
    if(sum!=sum1)printf("%d\\n",-1);return 0;
    for(int i=1;i<=n;++i)scanf("%s",c[i]+1);
    for(int i=1;i<=n;++i)
        for(int j=1;j<=m;++j)
        
            int w=(int)(c[i][j]-0);
            for(int k=1;k<=8;++k)
            
                int xx=i+dx[k];
                int yy=j+dy[k];
                if(!pos[xx][yy])continue;
                add(pos[i][j]+n*m*2,pos[xx][yy]+n*m,INF,1);
            
            if((!(a[i][j]^b[i][j]))||(!(w&1)))
            
                add(pos[i][j]+n*m,pos[i][j],w>>1,0);
                add(pos[i][j],pos[i][j]+n*m*2,w>>1,0);
            
            else
            
                --w;
                add(pos[i][j]+n*m,pos[i][j],(w>>1)+a[i][j],0);
                add(pos[i][j],pos[i][j]+n*m*2,(w>>1)+b[i][j],0);
            
        
    EK();
    if(maxflow!=sum)printf("%d\\n",-1);
    else printf("%d\\n",ans);
    return 0;

 

以上是关于交换棋子的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ-2668交换棋子 最小费用最大流

[CQOI2012]交换棋子(最小费用最大流)

bzoj2668 [cqoi2012]交换棋子

[bzoj2668] [洛谷P3159] [cqoi2012] 交换棋子

p3159 [CQOI2012]交换棋子

题解CQOI2012交换棋子