【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开发之功能模块--输入框随着键盘的位置移动而移动
废话不多说,先直接上效果图: 先熟悉一下在Cocoa框架中会用到的key键: 然后直接上Demo的源码截图: 看代码之前,补充说一句,Demo中的文本框以及文本框的背后灰色的View是通过storyb ...
- SQL范式
第一范式:确保每列的原子性(字段不可分). 如果每列(或者每个属性)都是不可再分的最小数据单元(也称为最小的原子单元),则满足第一范式. 释义: 1.每一列属性都是不可再分的属性值,确保每一列的原子性 ...
- DbVisualizer连接hbase
1.添加phoneix驱动 (1).点击Tools--->Driver Manager- (2).新建一个驱动,名称为phoenix(名称随意),选择phoenix的客户端驱动,驱动类如图所示 ...
- SQL周、日、月、年数据统计
本文只是记录在项目中用到的统计的SQL语句,记一笔以防忘了 /// <summary> /// 获取统计数据 /// </summary> /// <param name ...
- mongo学习笔记(一):增删改查
安装:我是按这篇来弄的 一.Insert 1.db.person.insert({"name":"jack","age":20}) 2.va ...
- Apache 安装配置详情
本次文章讲解Apache的安装和基本的配置 输入PHP环境搭建的一部分 PHP完整配置信息请参考 http://www.cnblogs.com/azhe-style/p/php_new_env_bui ...
- Log4J基础详解及示例大全
去年这个时候,为做软件工程的大作业就详细学过Log4J的用法了,时隔一年想要在新的项目中好好使用一下的时候,发现几乎全忘了,悲催啊-- 再上网查资料,总是不能找到一篇符合我的口味,拿来就能轻松上手,方 ...
- XCode6 开发本地化应用
使用 XCode 6 开发本地化时,第一步,不能忘记,否则在添加本地化文件时,可能会找不到简体中文. 此外,如果使用 NSLocalizedString(@"xxx", nil) ...
- redis配置文件redis.conf中文版
转账自:http://www.jb51.net/article/50605.htm # Redis示例配置文件 # 注意单位问题:当需要设置内存大小的时候,可以使用类似1k.5GB.4M这样的常见格式 ...
- javascript运算符语法概述
× 目录 [1]个数 [2]优先级 [3]结合性[4]类型[5]规则表 前面的话 javascript中的运算符大多由标点符号表示,少数由关键字表示,它们的语法言简意赅,它们的数量却着实不少.运算符始 ...