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 }
  • 相关阅读:
    强化学习的基本迭代方法
    基于文本描述的事务聚类
    学习强化学习之前需要掌握的3种技能
    其它 华硕 ASAU S4100U 系统安装 win10安装 重装系统 Invalid Partition Table 解决
    数据分析 一些基本的知识
    Python 取样式的内容 合并多个文件的样式 自定义样式
    电商 Python 生成补单公司需要的评论格式3
    SpringBlade 本地图片上传 生成缩略图
    SQL Server 字符串截取
    SpringBlade 本地图片上传
  • 原文地址:https://www.cnblogs.com/bztMinamoto/p/9510896.html
Copyright © 2011-2022 走看看