博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
2668: [cqoi2012]交换棋子
阅读量:5112 次
发布时间:2019-06-13

本文共 1994 字,大约阅读时间需要 6 分钟。

Description

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

Input

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

Output

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


写了一个很假的做法

但是居然正解也是这样的??

1437515-20190115153018716-1623107648.jpg

好吧好吧

那这题也太丧病了


先想一下这道题的基本建模思路,就是把它想象成一些黑点在一张图上流动,如果一个点初始时是黑色就从源点流一个流量一的边,如果遇到一个目标是黑色的点就可以流去汇点

初始版本 1.0 (甚至能得60分)

然后考虑拆两个点

1437515-20190115153701658-1159453618.png

没前途啊

考虑到一个位置上换来一个点然后再换走的话这个位置被换了2次

但是这个模型没法处理啊。。。

优化版本 1.5

拆成3个点!

1437515-20190115184328726-1889807616.png

怎么说呢。。。比1.0还没前途啊

因为如果这个点本来是黑色的但是它的流量是1

那么它就流不过去了。。。

正解 2.0

如果这个点就是黑色的就把2到3的流量改成(流量上限+1)/2不就完了

然后就喜提满分了??


#include
#include
#include
#include
#include
#define MP make_pair#define TS top().second#define M 1000001#define N 50000//#define gc getcharusing namespace std;priority_queue
>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

转载于:https://www.cnblogs.com/ZUTTER/p/10273635.html

你可能感兴趣的文章
Field部分参数设置含义
查看>>
剑指Offer——最小的K个数
查看>>
Silverlight 3 has Released!
查看>>
Python使用struct处理二进制(pack和unpack用法)
查看>>
查找数组中的最大值(最小值)及相对应的下标
查看>>
移动设备显示尺寸大全 CSS3媒体查询
查看>>
hihoCoder #1831 : 80 Days-RMQ (ACM/ICPC 2018亚洲区预选赛北京赛站网络赛)
查看>>
图片等比例缩放及图片上下剧中
查看>>
jQuery方法大全
查看>>
[转贴]安装ssh
查看>>
WebView加载网页详情
查看>>
【转载】Linux screen 命令详解
查看>>
dd命令 建立两颗一模一样的磁盘
查看>>
常用的jquery触屏手机页面特效代码下载
查看>>
background-clip,background-origin
查看>>
C# 如何创建一个Windows服务
查看>>
集群和分布式区别
查看>>
Android(java)学习笔记153:采用post请求提交数据到服务器(qq登录案例)
查看>>
Java基础知识强化101:Java 中的 String对象真的不可变吗 ?
查看>>
Android 高级UI设计笔记12:ImageSwitcher图片切换器
查看>>