zoukankan      html  css  js  c++  java
  • BZOJ2668:[CQOI2012]交换棋子(费用流)

    题目描述

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

    输入输出格式

    输入格式:

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

    输出格式:

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

    输入输出样例

    输入样例#1: 复制
    3 3
    110
    000
    001
    000
    110
    100
    222
    222
    222
    输出样例#1: 复制
    4

    题解

      费用流好题(说的清楚一点就是我根本不会做……)

      %%%大佬->这里

      首先考虑,我们可以把交换操作,看作是黑色的点在移动

      一个点往下移动的话,当前点和下方的点的交换次数都加一

      然后一条移动的路径,两端的点移动次数加一,中间的点移动次数加二

      如果把这个过程看做网络流的话,就会有一个问题。因为每一个点开始和结束的颜色可能不同,那么流入和流出也不同

      如果只有一个点,就没办法考虑交换次数的限制

      而且如果只拆成两个点的话,就没办法考虑路径两端的情况了

      那么我们把每一个点拆成三个点$left,now,right$,分别表示只有流入,有流入和流出,只有流出

      所以连边$left->now->right$

      然后相互能到达的点之间连边,容$inf$费$0$

      然后考虑如何解决流入流出不平衡

      如果开始为白,之后黑,那么流出必定比流入多一,开始黑,之后白,流入必定比流出多一,颜色一样,那么流入流出一样

      然后交换次数最少,在相邻的格子的边上加上费用

      若该点在初始图中是黑的、最终图中是白的,那么连边$(left,now,1,frac{limit}{2}),(now,right,1,frac{limit+1}{2})$

      若该点在初始图中是白的、最终图中是黑的,那么连边$(left,now,1,frac{limit+1}{2}),(now,right,1,frac{limit}{2})$

      若该点在初始图和最终图中颜色相同,那么连边$(left,now,1,frac{limit}{2}),(now,right,1,frac{limit}{2})$

      这样就可以保证流量限制了

      然后加源,往起始的所有黑点连边,加汇,让最终所有黑点往它连边

      然后在能互相到达的点之间连边

     1 //minamoto
     2 #include<iostream>
     3 #include<cstdio>
     4 #include<cstring>
     5 #include<queue>
     6 #define inf 0x3f3f3f3f
     7 #define l(i,j) ((i-1)*m+j)
     8 #define now(i,j) (((i-1)*m+j)+n*m)
     9 #define r(i,j) (((i-1)*m+j)+(n*m<<1))
    10 using namespace std;
    11 const int N=2005,M=50005;
    12 int dx[]={1,1,1,0,-1,-1,-1,0},dy[]={1,0,-1,-1,-1,0,1,1};
    13 int ver[M],Next[M],head[N],flow[M],edge[M],tot=1;
    14 int dis[N],disf[N],Pre[N],last[N],vis[N];
    15 int n,m,ans=0,S,T;
    16 queue<int> q;
    17 inline void add(int u,int v,int f,int e){
    18     ver[++tot]=v,Next[tot]=head[u],head[u]=tot,flow[tot]=f,edge[tot]=e;
    19     ver[++tot]=u,Next[tot]=head[v],head[v]=tot,flow[tot]=0,edge[tot]=-e;
    20 }
    21 bool spfa(){
    22     memset(dis,0x3f,sizeof(dis));
    23     q.push(S),dis[S]=0,disf[S]=inf,Pre[T]=-1;
    24     while(!q.empty()){
    25         int u=q.front();q.pop(),vis[u]=0;
    26         for(int i=head[u];i;i=Next[i]){
    27             int v=ver[i];
    28             if(flow[i]&&dis[v]>dis[u]+edge[i]){
    29                 dis[v]=dis[u]+edge[i],Pre[v]=u,last[v]=i;
    30                 disf[v]=min(disf[u],flow[i]);
    31                 if(!vis[v]) vis[v]=1,q.push(v);
    32             }
    33         }
    34     }
    35     return ~Pre[T];
    36 }
    37 int dinic(){
    38     int maxflow=0;
    39     while(spfa()){
    40         int u=T;maxflow+=disf[T],ans+=disf[T]*dis[T];
    41         while(u!=S){
    42             flow[last[u]]-=disf[T];
    43             flow[last[u]^1]+=disf[T];
    44             u=Pre[u];
    45         }
    46     }
    47     return maxflow;
    48 }
    49 int x1[25][25],x2[25][25],t1,t2;
    50 char s[30];
    51 int main(){
    52     scanf("%d%d",&n,&m);
    53     S=0,T=n*m*3+1;
    54     for(int i=1;i<=n;++i){
    55         scanf("%s",s+1);
    56         for(int j=1;j<=m;++j)
    57         if(s[j]=='1'){
    58             ++t1,add(S,now(i,j),1,0);
    59             x1[i][j]=1;
    60         }
    61     }
    62     for(int i=1;i<=n;++i){
    63         scanf("%s",s+1);
    64         for(int j=1;j<=m;++j)
    65         if(s[j]=='1'){
    66             ++t2,add(now(i,j),T,1,0);
    67             x2[i][j]=1;
    68         }
    69     }
    70     if(t1!=t2) return puts("-1"),0;
    71     for(int i=1;i<=n;++i){
    72         scanf("%s",s+1);
    73         for(int j=1;j<=m;++j){
    74             t2=s[j]-'0';
    75             if(x1[i][j]==x2[i][j])
    76             add(l(i,j),now(i,j),t2/2,0),add(now(i,j),r(i,j),t2/2,0);
    77             else if(x1[i][j]&&!x2[i][j])
    78             add(l(i,j),now(i,j),t2/2,0),add(now(i,j),r(i,j),(t2+1)/2,0);
    79             else
    80             add(l(i,j),now(i,j),(t2+1)/2,0),add(now(i,j),r(i,j),t2/2,0);
    81         }
    82     }
    83     for(int i=1;i<=n;++i)
    84     for(int j=1;j<=m;++j)
    85     for(int k=0;k<8;++k){
    86         int ti=i+dx[k],tj=j+dy[k];
    87         if(ti<1||ti>n||tj<1||tj>m) continue;
    88         add(r(i,j),l(ti,tj),inf,1);
    89     }
    90     if(dinic()!=t1) return puts("-1"),0;
    91     printf("%d
    ",ans);
    92     return 0;
    93 }
  • 相关阅读:
    小编见过的验证方式汇总
    Burp Suite Professional 针对APP抓包篡改数据提交【安全】
    关于Chrome 67 以后版本无法离线安装扩展的解决方法
    Postman 中上传图片的接口怎么做参数化呢?
    字符串-不同的编码格式下所占用的字节数【转】
    Java RandomAccessFile用法 【转】
    URI和URL的区别 【转】
    Java多线程-线程的同步与锁【转】
    浅谈Java多线程的同步问题 【转】
    Java中浮点数的精度问题 【转】
  • 原文地址:https://www.cnblogs.com/bztMinamoto/p/9510896.html
Copyright © 2011-2022 走看看