题目描述

有一个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




好像所有的没有思路的题都能用毒瘤的网络流来搞一下,这题真的毒瘤,第一次见拆三个点的看到一个点最多参与几次交换,就应该想到拆点限流,然后最后问你最先的代价,应该可以联想到费用这一块,那就向费用流这块搞啊,这题的建模是真的难想,所以说就不详细写了,细节挺多的。然后就是不用担心一个1到达目标的时候,打乱的别的1,因为这时通过交换两个点的先后顺序来避免这个问题。放个网址:   https://www.luogu.org/problemnew/solution/P3159



  1 #include<queue>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<iostream>
  5 #include<algorithm>
  6 #define MAXN 2010
  7 #define MAXM 64010
  8 #define INF 0x3f3f3f3f
  9 #define fpop(x) x.front();x.pop()
 10 using namespace std;
 11
 12 int pre_node[MAXN],pre_edge[MAXN];
 13
 14 char ch,mp_bg[25][25],mp_ed[25][25];
 15
 16 int n,m,cnt=-1,dis[MAXN],vis[MAXN],flow[MAXN],head[MAXN],maxf[25][25];
 17
 18 struct edge{
 19     int nxt,to,w,f;
 20 }e[MAXM];
 21
 22 inline int _bg(int x,int y){return n*m*0+(x-1)*m+y;}//起始点[x,y]的编号
 23 inline int _ed(int x,int y){return n*m*1+(x-1)*m+y;}//目标点[x,y]的编号
 24 inline int _inn(int x,int y){return n*m*2+(x-1)*m+y;}//棋盘[x,y]的Inn点编号
 25 inline int _mid(int x,int y){return n*m*3+(x-1)*m+y;}//棋盘[x,y]的mid点标号
 26 inline int _out(int x,int y){return n*m*4+(x-1)*m+y;}//棋盘[x,y]的Out点编号
 27
 28 inline bool in_map(int x,int y){
 29     return 1<=x && x<=n && 1<=y && y<=m;
 30 }//判断是否越界
 31
 32 inline void add_edge(int from,int to,int flw,int val){
 33     e[++cnt].nxt=head[from];
 34     e[cnt].to=to;
 35     e[cnt].f=flw;
 36     e[cnt].w=val;
 37     head[from]=cnt;
 38 }
 39
 40 queue<int>que;
 41
 42 inline bool spfa(int s,int t){
 43     memset(vis,0,sizeof(vis));
 44     memset(dis,0x3f,sizeof(dis));
 45     memset(flow,0x3f,sizeof(flow));
 46     que.push(s); vis[s]=true; dis[s]=0;
 47     while(!que.empty()){
 48         int u=fpop(que);
 49         for(int i=head[u];~i;i=e[i].nxt){
 50             int v=e[i].to;
 51             if(dis[v]>dis[u]+e[i].w && e[i].f){
 52                 dis[v]=dis[u]+e[i].w;
 53                 flow[v]=min(flow[u],e[i].f);
 54                 pre_node[v]=u;
 55                 pre_edge[v]=i;
 56                 vis[v]=true;que.push(v);
 57             }
 58         }
 59     }
 60     return dis[t]!=INF;
 61 }
 62
 63 int mv[8][2]={{1,0},{-1,0},{0,1},{0,-1},{1,1},{1,-1},{-1,1},{-1,-1}};
 64
 65 int main(){
 66     memset(head,-1,sizeof(head));
 67     scanf("%d%d",&n,&m);
 68     for(int i=1;i<=n;++i){
 69         for(int j=1;j<=m;++j){
 70             scanf(" %c",&mp_bg[i][j]);
 71         }
 72     }
 73     for(int i=1;i<=n;++i){
 74         for(int j=1;j<=m;++j){
 75             scanf(" %c",&mp_ed[i][j]);
 76         }
 77     }
 78     for(int i=1;i<=n;++i){
 79         for(int j=1;j<=m;++j){
 80             scanf(" %c",&ch);
 81             maxf[i][j]=ch-'0';
 82             //最大经过次数
 83         }
 84     }
 85     //输入起始态和目标态棋盘
 86     int s=0,t=n*m*5+1;
 87     int cnt_1=0,cnt_2=0;
 88     for(int i=1;i<=n;++i){
 89         for(int j=1;j<=m;++j){
 90             if(mp_bg[i][j]==mp_ed[i][j]){
 91                 add_edge(_inn(i,j),_mid(i,j),maxf[i][j]/2,0);
 92                 add_edge(_mid(i,j),_inn(i,j),000000000000,0);
 93
 94                 add_edge(_mid(i,j),_out(i,j),maxf[i][j]/2,0);
 95                 add_edge(_out(i,j),_mid(i,j),000000000000,0);
 96             }else{
 97                 if(mp_bg[i][j]=='1'){
 98                     add_edge(_inn(i,j),_mid(i,j),(maxf[i][j]+0)/2,0);
 99                     add_edge(_mid(i,j),_inn(i,j),000000000000,0);
100
101                     add_edge(_mid(i,j),_out(i,j),(maxf[i][j]+1)/2,0);
102                     add_edge(_out(i,j),_mid(i,j),000000000000,0);
103                 }
104                 if(mp_ed[i][j]=='1'){
105                     add_edge(_inn(i,j),_mid(i,j),(maxf[i][j]+1)/2,0);
106                     add_edge(_mid(i,j),_inn(i,j),000000000000,0);
107
108                     add_edge(_mid(i,j),_out(i,j),(maxf[i][j]+0)/2,0);
109                     add_edge(_out(i,j),_mid(i,j),000000000000,0);
110                 }
111             }
112
113             if(mp_bg[i][j]=='1'){
114                 ++cnt_1;
115                 //连接源点到初始点     f=1 w=0;
116                 add_edge(s,_mid(i,j),1,0);
117                 add_edge(_mid(i,j),s,0,0);
118                 //连接起始点到棋盘
119               //  add_edge(_bg(i,j),_mid(i,j),1,0);
120               //  add_edge(_mid(i,j),_bg(i,j),0,0);
121             }
122             if(mp_ed[i][j]=='1'){
123                 ++cnt_2;
124                 //连接终结点到汇点     f=1 w=0;
125                 add_edge(_mid(i,j),t,1,0);
126                 add_edge(t,_mid(i,j),0,0);
127                 //连接棋盘到终结点
128               //  add_edge(_mid(i,j),_ed(i,j),1,0);
129                // add_edge(_ed(i,j),_mid(i,j),0,0);
130             }
131             //棋盘的八连通边  f=INF w=1;
132             for(int k=0;k<8;++k){
133                 int ni=i+mv[k][0];
134                 int nj=j+mv[k][1];
135                 if(in_map(ni,nj)){
136                     //从点[i,j]的out连接点[ni,nj]的inn
137                     add_edge(_out(i,j),_inn(ni,nj),INF,+1);
138                     add_edge(_inn(ni,nj),_out(i,j),000,-1);
139                 }
140             }
141         }
142     }
143     //棋子数变动->No solution
144     if(cnt_1!=cnt_2){
145         puts("-1");
146         return 0;
147     }
148     //然后跑费用流
149     int max_flow=0,min_cost=0;
150     while(spfa(s,t)){
151         max_flow+=flow[t];
152         min_cost+=flow[t]*dis[t];
153         int u=t;
154         while(u!=s){
155             e[pre_edge[u]^0].f-=flow[t];
156             e[pre_edge[u]^1].f+=flow[t];
157             u=pre_node[u];
158         }
159     }
160     if(max_flow!=cnt_1){
161         puts("-1");
162         return 0;
163     }
164     printf("%d\n",min_cost);
165 }

转载于:https://www.cnblogs.com/zhangbuang/p/10638102.html

P3159 [CQOI2012]交换棋子(费用流)相关推荐

  1. 洛谷P3159 [CQOI2012]交换棋子

    巧妙的拆点方式,首先把1看成黑点,0看成空的,几次交换就可以看成一条路径 1)从容量上看,这条路径为1-2-2-2-2-2----2-1 2)从费用上看,这条路径每条边费用都是1 于是用一种巧妙的拆点 ...

  2. BZOJ 2668: [cqoi2012]交换棋子

    2668: [cqoi2012]交换棋子 Time Limit: 3 Sec  Memory Limit: 128 MB Submit: 1112  Solved: 409 [Submit][Stat ...

  3. [CQOI2012]交换棋子【网络流】【费用流】

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

  4. 洛谷 P3159(BZOJ 2668)[CQOI2012]交换棋子

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

  5. BZOJ2668:[CQOI2012]交换棋子——题解

    http://www.lydsy.com/JudgeOnline/problem.php?id=2668 https://www.luogu.org/problemnew/show/P3159#sub ...

  6. 2668: [cqoi2012]交换棋子

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

  7. bzoj2668 [cqoi2012]交换棋子

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

  8. 【BZOJ-2668】交换棋子 最小费用最大流

    2668: [cqoi2012]交换棋子 Time Limit: 3 Sec  Memory Limit: 128 MB Submit: 1055  Solved: 388 [Submit][Stat ...

  9. P3159-[CQOI2012]交换棋子【费用流】

    正题 题目链接:https://www.luogu.com.cn/problem/P3159 题目大意 n∗mn*mn∗m的棋盘,每个格子有黑子或白子,每次可以交换两个位置的棋,给出起始态和最终态和每 ...

最新文章

  1. 【运筹学】线性规划 人工变量法 ( 人工变量法案例 | 第一次迭代 | 中心元变换 | 检验数计算 | 选择入基变量 | 选择出基变量 )
  2. 再学 GDI+[68]: 路径画刷(8) - SetBlendTriangularShaped、SetBlendBellShape
  3. (转)upper_bound()与lower_bound()使用方法
  4. P4068 [SDOI2016]数字配对
  5. SAP UI5 货币金额显示的格式化逻辑
  6. java soap协议头_自己调用webservice方法总结(带请求头SoapHeader)
  7. 深入浅出讲解C语言#define宏定义应用及使用方法
  8. jQuery选择器,用逗号分隔的时候需要注意范围问题
  9. 服务器 消息 208,在MSSQL2000里边 对象名 'sys.servers' 无效 服务器: 消息 208,级别 16,状态 1,行 1...
  10. 正则表达式匹配日期时间
  11. 解剖SQLSERVER 第八篇 OrcaMDF 现在支持多数据文件的数据库(译)
  12. 【LeetCode】数组-1(643)-返回规定长度k的最大子数组的平均数
  13. 0x00007FFE9071C408 (ucrtbase.dll) (xxx.exe 中)处有未经处理的异常: 将一个无效参数传递给了将无效参数视为严重错误的函数。
  14. hdu2859 Phalanx(线性dp)
  15. ssm大学生兼职论坛
  16. 搜索 SAP成都研究院廖婧:SAP C4C社交媒体集成概述
  17. 法国iut计算机转专业,法国艺术留学能不能够申请转专业.docx
  18. WordPress柒比贰B2 V2.9.9自媒体主题模板
  19. c语言实验植物与颜色,植物的光合作用曲线比较.doc
  20. [附源码]计算机毕业设计JAVA同德佳苑物业管理系统论文

热门文章

  1. 输出整数的位数、按位输出(两种)以及逆序输出
  2. exe4j打包exe_Java日常实用技巧之程序打包为可执行文件
  3. c语言二元运算符大全,C语言运算符大全
  4. java怎么防止表单重复提交_如何防止表单重复提交
  5. 应用存储和持久化数据卷:存储快照与拓扑调度(至天)
  6. Canonical 开源 MicroK8 | 云原生生态周报 Vol. 25
  7. python 参数类型的多态_【Python】面向对象:类与对象\封装\继承\多态
  8. mysql正则表达式regexp_mysql - 正则表达式 RegExp
  9. centos一键清理磁盘空间_磁盘空间不够用?教你一键清理电脑重复文件
  10. c语言线性表顺序存储实验小结,数据结构学习笔记-线性表顺序存储(C语言实现)...