【BZOJ-2668】交换棋子 最小费用最大流
2668: [cqoi2012]交换棋子
Time Limit: 3 Sec Memory Limit: 128 MB
Submit: 1055 Solved: 388
[Submit][Status][Discuss]
Description
Input
Output
Sample Input
110
000
001
000
110
100
222
222
222
Sample Output
HINT
Source
Solution
这是一道建图比较有趣的费用流.
想到用费用流比较容易,很显然,连法必然是S连向原图中的黑点,新图中的黑点连向T,问题在于中间的连边,如何利用容量限制两个点。
自己一开始立马想到拆点,但是是很naive的一拆二,限制容量,但这样并不可以。
实际上这个题需要一个点拆成3个点,我们把点$x$拆成$x_{1},x_{2},x_{3}$,并连出$x_{1}-->x_{2}-->x_{3}$
其中$x_{1}-->x_{2}$表示$x$这个点最多流入的流量,$x_{2}-->x_{3}$表示$x$这个点最多流出的流量。
对于一个点$x$,如果只是原图的黑点,那么限制$<x_{1},x_{2}>:cap=\frac{use[x]}{2};cost=0 ; <x_{2},x_{3}>:cap=\frac{use[x]+1}{2};cost=0$
并且连$S-->x_{2} : cap=1;cost=0$
对于一个点$x$,如果只是新图的黑点,那么限制$<x_{1},x_{2}>:cap=\frac{use[x]+1}{2};cost=0 ; <x_{2},x_{3}>:cap=\frac{use[x]}{2};cost=0$
并且连$x_{2}-->T : cap=1;cost=0$
如果一个点$x$,如果在原图和新图中都是白点或者都是黑点,那么我们限制$<x_{1},x_{2}>:cap=\frac{use[x]}{2};cost=0 ; <x_{2},x_{3}>:cap=\frac{use[x]}{2};cost=0$
对于图中的八连通格两两$x ; y$,连边$x_{3}-->y_{1} :cap=INF ; cost=1$流经此边,表示交换一次。
上述的限制方法,实际上是对网格的每个位置的流量变化进行讨论得到的,因为是一个最值情况,所以很多流入流出限制都无法完全流满。
Code
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
using namespace std;
#define MAXM 100010
#define MAXN 2000
int N,M,used[][];
char st[][],ed[][],us[][];
struct EdgeNode{int next,to,cap,cost;}edge[MAXM];
int cnt=,head[MAXN];
inline void AddEdge(int u,int v,int w,int c) {cnt++; edge[cnt].next=head[u]; head[u]=cnt; edge[cnt].to=v; edge[cnt].cap=w; edge[cnt].cost=c;}
inline void InsertEdge(int u,int v,int w,int c) {AddEdge(u,v,w,c); AddEdge(v,u,,-c);}
int dis[MAXN],S,T,Cost,Flow;
bool mark[MAXN];
#define INF 0x7fffffff
inline bool SPFA()
{
memset(mark,,sizeof(mark));
for (int i=S; i<=T; i++) dis[i]=INF;
queue<int>q;
q.push(S); dis[S]=; mark[S]=;
while (!q.empty())
{
int now=q.front(); q.pop(); mark[now]=;
for (int i=head[now]; i; i=edge[i].next)
if (edge[i].cap && dis[edge[i].to]>dis[now]+edge[i].cost)
{
dis[edge[i].to]=dis[now]+edge[i].cost;
if (!mark[edge[i].to]) q.push(edge[i].to),mark[edge[i].to]=;
}
}
return dis[T]!=INF;
}
inline int DFS(int loc,int low)
{
mark[loc]=;
if (loc==T) return low;
int used=,w;
for (int i=head[loc]; i; i=edge[i].next)
if (edge[i].cap && !mark[edge[i].to] && dis[edge[i].to]==dis[loc]+edge[i].cost)
{
w=DFS(edge[i].to,min(edge[i].cap,low-used));
edge[i].cap-=w; edge[i^].cap+=w; used+=w; Cost+=w*edge[i].cost;
if (low==used) return used;
}
return used;
}
inline int zkw()
{
int re=;
while (SPFA())
{
mark[T]=;
while (mark[T]) memset(mark,,sizeof(mark)),re+=DFS(S,INF);
}
return re;
}
int id[][][],ID,black,white;
int dx[]={-,-,-,,,,,},dy[]={-,,,-,,-,,};
inline bool check(int x,int y) {return x>= && x<=N && y>= && y<=M;}
void BuildGraph()
{
for (int i=; i<=N; i++)
for (int j=; j<=M; j++)
for (int k=; k<=; k++)
id[i][j][k]=++ID;
S=,T=ID+;
for (int i=; i<=N; i++)
for (int j=; j<=M; j++)
{
if (st[i][j]=='' && ed[i][j]=='')
black++,
InsertEdge(S,id[i][j][],,),
InsertEdge(id[i][j][],id[i][j][],used[i][j]/,),
InsertEdge(id[i][j][],id[i][j][],(used[i][j]+)/,);
if (st[i][j]=='' && ed[i][j]=='')
white++,
InsertEdge(id[i][j][],T,,),
InsertEdge(id[i][j][],id[i][j][],(used[i][j]+)/,),
InsertEdge(id[i][j][],id[i][j][],used[i][j]/,);
if (st[i][j]==ed[i][j])
InsertEdge(id[i][j][],id[i][j][],used[i][j]/,),
InsertEdge(id[i][j][],id[i][j][],used[i][j]/,);
}
for (int i=; i<=N; i++)
for (int j=; j<=M; j++)
for (int x,y,k=; k<; k++)
{
x=i+dx[k],y=j+dy[k];
if (check(x,y)) InsertEdge(id[i][j][],id[x][y][],INF,);
}
}
int main()
{
scanf("%d%d",&N,&M);
for (int i=; i<=N; i++) scanf("%s",st[i]+);
for (int i=; i<=N; i++) scanf("%s",ed[i]+);
for (int i=; i<=N; i++) scanf("%s",us[i]+);
for (int i=; i<=N; i++)
for (int j=; j<=M; j++) used[i][j]=us[i][j]-'';
BuildGraph();
Flow=zkw();
printf("%d\n",black==white? (Flow==black? Cost : -) : -);
return ;
}
脑残RE了好几次...
【BZOJ-2668】交换棋子 最小费用最大流的更多相关文章
- BZOJ 2668 [cqoi2012]交换棋子 | 最小费用最大流
传送门 BZOJ 2668 题解 同时分别限制流入和流出次数,所以把一个点拆成三个:入点in(x).中间点mi(x).出点ou(x). 如果一个格子x在初始状态是黑点,则连(S, mi(x), 1, ...
- BZOJ 2668 交换棋子(费用流)
题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=2668 题意:有一个n行m列的黑白棋盘,你每次可以交换两个相邻格子中的棋子,最终达到目标状 ...
- BZOJ 1927 星际竞速(最小费用最大流)
题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=1927 题意:一个图,n个点.对于给出的每条边 u,v,w,表示u和v中编号小的那个到编号 ...
- BZOJ 2424: [HAOI2010]订货(最小费用最大流)
最小费用最大流..乱搞即可 ------------------------------------------------------------------------------ #includ ...
- [BZOJ 2668] 交换棋子
Link: BZOJ 2668 传送门 Solution: 重点在于对于每条转移路径:首尾算一次,中间节点算两次 可以一点拆三点,将原流量拆成入流量和出流量 但其实也可以就拆两点,分前后是否是一首尾点 ...
- BZOJ 1070: [SCOI2007]修车 [最小费用最大流]
1070: [SCOI2007]修车 Time Limit: 1 Sec Memory Limit: 128 MBSubmit: 4936 Solved: 2032[Submit][Status] ...
- bzoj 1061 志愿者招募(最小费用最大流)
[Noi2008]志愿者招募 Time Limit: 20 Sec Memory Limit: 162 MBSubmit: 3792 Solved: 2314[Submit][Status][Di ...
- BZOJ 3550 Vacation(最小费用最大流)
题目链接:http://www.lydsy.com:808/JudgeOnline/problem.php?id=3550 题意:给出3×n个数字,从中选出一些数字,要求每连续的n个数字中选出的数字个 ...
- BZOJ 2597 剪刀石头布(最小费用最大流)(WC2007)
Description 在一些一对一游戏的比赛(如下棋.乒乓球和羽毛球的单打)中,我们经常会遇到A胜过B,B胜过C而C又胜过A的有趣情况,不妨形象的称之为剪刀石头布情况.有的时候,无聊的人们会津津乐道 ...
随机推荐
- IOS开发之Bug--使用xib的自动布局和代码中修改遇到的bug
首先,在xib中约束了宽高22,但是需要代码动态重设,所以一开始如下设置,但是实际显示的仍然是22,而不是重设的值: 然后直接拿xib的将布局约束对象拖线重新通过代码重设约束值,虽然打印的结果宽高值是 ...
- 教你开发asp.net的单点登录系统
单点登录系统,简称SSO.以下是我花了几个小时写的一个简单实现.特把实现思路和大家分享. 背景:某项目使用ASP.NET MemberShip来做会员系统,需要同时登录多个系统.而项目的开发人员无法在 ...
- socket-详细分析No buffer space available
关键词:socket,tcp三次握手,tcp四次握手,2MSL最大报文生存时间,LVS,负载均衡 新年上班第一天,突然遇到一个socket连接No buffer space available的问题, ...
- 2016款MACBOOK PRO触控条版 安装WIN10初体验 及 无奈退货记
新的2016MBP终于发布了,作为把苹果电脑装WIN使用的人,等候很久之后,终于可以行动了. 黄山松 (Tom Huang) 发表于博客园http://www.cnblogs.com/tomview/ ...
- Android 分享到微信
/** * 分享信息到朋友 * * @param file,假如图片的路径为path,那么file = new File(path); */ private void shareToFriend(Fi ...
- Openstack基本命令
Openstack有数量众多的命令行工具(CLI),用来执行各式各样的管理任务,例如VM管理.存储管理.网络管理.本文描述用Openstack CLI工具执行如下任务: 设置环境变量 使用内置帮助 创 ...
- Eclipse不自动编译java文件的终极解决方案
最近我的eclipse经常犯傻,项目中总是有很多,启动项目也是没有启动类.查了下项目中生成的class文件,我靠竟然没有,或者还是以前的.原来是eclipse犯傻了,它没帮我自动编译java文件.一般 ...
- nginx 日志相关配置总结
设置位于nginx.conf: log_format main '$server_name $remote_addr - $remote_user [$time_local] &q ...
- 帆软报表FineReport SQLServer数据库连接失败常见解决方案
1. 问题描述 帆软报表FineReport客户端连接SQLServer(2000.2005等),常常会出现如下错误:com.microsoft.sqlserver.jdbc.SQLServerExc ...
- 疑似easyui本身bug:easyui时间控件问题,试了几个版本都不行
最近发现easyui时间控件的值格式不支持带斜杠的日期(2016/10/31),必须是2016-10-31这类的才能正常使用,否则默认初始化为当前时间 <input id="Retur ...