2668: [cqoi2012]交换棋子
Description
有一个n行m列的黑白棋盘,你每次可以交换两个相邻格子(相邻是指有公共边或公共顶点)中的棋子,最终达到目标状态。要求第i行第j列的格子只能参与mi,j次交换。
Input
第一行包含两个整数n,m(1<=n, m<=20)。以下n行为初始状态,每行为一个包含m个字符的01串,其中0表示黑色棋子,1表示白色棋子。以下n行为目标状态,格式同初始状态。以下n行每行为一个包含m个0~9数字的字符串,表示每个格子参与交换的次数上限。
Output
输出仅一行,为最小交换总次数。如果无解,输出-1。
写了一个很假的做法
但是居然正解也是这样的??
好吧好吧
那这题也太丧病了
先想一下这道题的基本建模思路,就是把它想象成一些黑点在一张图上流动,如果一个点初始时是黑色就从源点流一个流量一的边,如果遇到一个目标是黑色的点就可以流去汇点
初始版本 1.0 (甚至能得60分)
然后考虑拆两个点
没前途啊
考虑到一个位置上换来一个点然后再换走的话这个位置被换了2次
但是这个模型没法处理啊。。。
优化版本 1.5
拆成3个点!
怎么说呢。。。比1.0还没前途啊
因为如果这个点本来是黑色的但是它的流量是1
那么它就流不过去了。。。
正解 2.0
如果这个点就是黑色的就把2到3的流量改成(流量上限+1)/2
不就完了
然后就喜提满分了??
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#define MP make_pair
#define TS top().second
#define M 1000001
#define N 50000
//#define gc getchar
using namespace std;priority_queue<pair<int,int> >q;
int uu,a[M],t,n,m,k,ver[M],edge[M],head[N],nex[M],cnt=1,d[N],h[N],c[M],g[N],x,y,z,s,b[N],cur[N],ans,cost,w[M];
void add(int x,int y,int co,int z)
{ver[++cnt]=y; nex[cnt]=head[x]; head[x]=cnt; edge[cnt]=z; c[cnt]=co;ver[++cnt]=x; nex[cnt]=head[y]; head[y]=cnt; edge[cnt]=0; c[cnt]=-co;
}bool dji()
{while(q.size()) q.pop();memset(d,0,sizeof(d)); memset(g,0x3f,sizeof(g)); memset(b,0,sizeof(b));d[0]=1; g[0]=0; q.push(MP(0,0));while(q.size()){while(q.size() && b[q.TS]) q.pop();if(!q.size()) break;int x=q.TS; q.pop(); b[x]=1;for(int i=head[x];i;i=nex[i])if(edge[i] && g[ver[i]]>g[x]+c[i]+h[x]-h[ver[i]]){g[ver[i]]=g[x]+c[i]+h[x]-h[ver[i]];d[ver[i]]=d[x]+1;q.push(MP(-g[ver[i]],ver[i]));}}if(g[t]<0x3f3f3f3f) return 1;return 0;
}int dinic(int x,int flow)
{if(x==t || !flow) return flow;int re=flow, k;for(int& i=cur[x];i && re;i=nex[i])if(edge[i] && d[ver[i]]==d[x]+1 && g[ver[i]]==g[x]+c[i]+h[x]-h[ver[i]]){k=dinic(ver[i],min(re,edge[i]));re-=k; edge[i]-=k; edge[i^1]+=k;if(!k) d[ver[i]]=0;} return flow-re;
}int main()
{scanf("%d%d",&n,&m); t=n*m*3+1;for(int i=0;i<n;i++) for(int j=1;j<=m;j++) {scanf("%1ld",&k);if(k) a[i*m+j]=1, uu+=1;}for(int i=0;i<n;i++)for(int j=1;j<=m;j++){scanf("%1ld",&k);if(k) w[i*m+j]=1, uu-=1;if(i) add(i*m+j+n*m*2,(i-1)*m+j,1,0x3f3f3f3f);if(j!=1) add(i*m+j+n*m*2,i*m+j-1,1,0x3f3f3f3f);if(i && j!=1) add(i*m+j+n*m*2,(i-1)*m+j-1,1,0x3f3f3f3f);if(i && j!=m) add(i*m+j+n*m*2,(i-1)*m+j+1,1,0x3f3f3f3f);if(j!=m) add(i*m+j+n*m*2,i*m+j+1,1,0x3f3f3f3f);if(i!=n-1) add(i*m+j+n*m*2,(i+1)*m+j,1,0x3f3f3f3f);if(j!=m && i!=n-1) add(i*m+j+n*m*2,(i+1)*m+j+1,1,0x3f3f3f3f);if(j!=1 && i!=n-1) add(i*m+j+n*m*2,(i+1)*m+j-1,1,0x3f3f3f3f); }if(uu!=0){printf("-1"); return 0;}for(int i=1;i<=n*m;i++) {if(w[i]) add(i+n*m,t,0,1);if(a[i]) add(0,i,0,1); }for(int i=0;i<n;i++)for(int j=1;j<=m;j++){scanf("%1ld",&k);if(k)add(i*m+j,i*m+j+n*m,0,k);if(k && (w[i*m+j]||a[i*m+j])) add(i*m+j+n*m,i*m+j+n*m*2,0,(k+1)/2);else add(i*m+j+n*m,i*m+j+n*m*2,0,k/2);}while(dji()){memcpy(cur,head,sizeof(head)); z=ans;while(k=dinic(0,0x3f3f3f3f)) ans+=k;for(int i=1;i<=t;i++) h[i]+=g[i];cost+=(ans-z)*h[t];}printf("%d",cost);
}
转载于:https://www.cnblogs.com/ZUTTER/p/10273635.html
2668: [cqoi2012]交换棋子相关推荐
- BZOJ 2668: [cqoi2012]交换棋子
2668: [cqoi2012]交换棋子 Time Limit: 3 Sec Memory Limit: 128 MB Submit: 1112 Solved: 409 [Submit][Stat ...
- 洛谷 P3159(BZOJ 2668)[CQOI2012]交换棋子
有一个\(n\)行\(m\)列的黑白棋盘,你每次可以交换两个相邻格子(相邻是指有公共边或公共顶点)中的棋子,最终达到目标状态.要求第\(i\)行第\(j\)列的格子只能参与\(m[i][j]\)次交换 ...
- BZOJ2668:[CQOI2012]交换棋子——题解
http://www.lydsy.com/JudgeOnline/problem.php?id=2668 https://www.luogu.org/problemnew/show/P3159#sub ...
- P3159 [CQOI2012]交换棋子(费用流)
题目描述 有一个n行m列的黑白棋盘,你每次可以交换两个相邻格子(相邻是指有公共边或公共顶点)中的棋子,最终达到目标状态.要求第i行第j列的格子只能参与mi,j次交换. 输入输出格式 输入格式: 第 ...
- [CQOI2012]交换棋子【网络流】【费用流】
题目描述 有一个n行m列的黑白棋盘,你每次可以交换两个相邻格子(相邻是指有公共边或公共顶点)中的棋子,最终达到目标状态.要求第i行第j列的格子只能参与mi,j次交换. 输入输出格式 输入格式: 第一行 ...
- bzoj2668 [cqoi2012]交换棋子
Description 有一个n行m列的黑白棋盘,你每次可以交换两个相邻格子(相邻是指有公共边或公共顶点)中的棋子,最终达到目标状态.要求第i行第j列的格子只能参与mi,j次交换. Input 第一行 ...
- 洛谷P3159 [CQOI2012]交换棋子
巧妙的拆点方式,首先把1看成黑点,0看成空的,几次交换就可以看成一条路径 1)从容量上看,这条路径为1-2-2-2-2-2----2-1 2)从费用上看,这条路径每条边费用都是1 于是用一种巧妙的拆点 ...
- 【BZOJ-2668】交换棋子 最小费用最大流
2668: [cqoi2012]交换棋子 Time Limit: 3 Sec Memory Limit: 128 MB Submit: 1055 Solved: 388 [Submit][Stat ...
- P3159-[CQOI2012]交换棋子【费用流】
正题 题目链接:https://www.luogu.com.cn/problem/P3159 题目大意 n∗mn*mn∗m的棋盘,每个格子有黑子或白子,每次可以交换两个位置的棋,给出起始态和最终态和每 ...
最新文章
- python批量提取word指定内容_使用python批量读取word文档并整理关键信息到excel表格的实例...
- 第七章、Linux 文件与目录管理
- 热修复框架AndFix【源码阅读】
- 函数函数sigaction、signal
- 有关进程的一些基本概念
- LeetCode 1812. 判断国际象棋棋盘中一个格子的颜色
- 在head标签内css代码,怎么在head区域引入css
- android编辑框显示,为EditText输入框加上提示信息
- JavaScript 媒体查询库 enquire.js
- HTTP协议状态码详解(HTTP Status Code)(转)
- iOS CocoaPods自动管理第三方开源库
- DevExpress WPF控件3D打印应用场景 - 实现3D打印系统可视化窗口
- 黑马程序员—黑马程序员CEO方立勋致全体员工和同学们的公开信
- 常考的java数据库笔试题
- 技术可行性分析注意哪些内容?
- 结构体的定义以及使用
- 去除百度搜索列表中广告的方法-电脑端
- 宁德时代钠电池雷声大,雨点小?
- 【ice】飞冰快速上手笔记
- java基础知识粗略整理
热门文章
- How to study foreign language
- Linux的基本学习(十三)——进程管理(上)
- mysql优化 个人笔记 非礼勿扰 -m04
- 黑盒测试方法实例分析
- 自己编写字符串复制函数
- The group member's supported protocols are incompatible with those of existing members
- qt repaint 用法_qt的repaint的问题
- linux网络编程-很全的
- 网站加强用户停留时间的方法
- [LibreOJ Round #11]Misaka Network 与求和