【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的有趣情况,不妨形象的称之为剪刀石头布情况.有的时候,无聊的人们会津津乐道 ...
随机推荐
- 漫谈C语言结构体struct、公用体union空间占用
先用代码说话: #include<stdio.h> union union_data0{ int a ;//本身占用4个字节 char b ;//本身占用1个字节 int c ; }; u ...
- SQL SERVER导出特殊格式的平面文件
有时候我们需要将SQL SERVER的数据一次性导入到ORACLE中,对于数据量大的表.我一般习惯先从SQL SERVER导出特殊格式的平面文件(CSV或TXT),然后用SQL*Loader装载数据到 ...
- Linux服务开机自启动设置
Linux中也有类似于Window中的开机自启动服务,主要是通过chkconfig命令来设置.它主要用来更新(启动或停止)和查询系统服务的运行级信息.谨记chkconfig不是立即自动禁止或激活一个服 ...
- WinForm:DataGridView新增加行
1.不显示最下面的新行 通常 DataGridView 的最下面一行是用户新追加的行(行头显示 * ).如果不想让用户新追加行即不想显示该新行,可以将 DataGridView 对象的 AllowUs ...
- MongoDB学习笔记~自己封装的Curd操作(按需更新的先决条件)
回到目录 我们上一讲中介绍了大叔封装的Mongo仓储,其中介绍了几个不错的curd操作,而对于按需更新内部子对象,它是有条件的,即你的子对象不能为null,也就是说,我们在建立主对象时,应该为子对象赋 ...
- Oracle 12c 使用scott等普通用户的方法
目录: 一.前言 二.使用普通用户 三.自动启动PDB 一.前言 最近电脑上安装了oracle 12c数据库,想体验下新特性.安装完后,便像11g一样在dos窗口进行下面的操作: SQL Produc ...
- 使用 python 实现 wc 命令程序的基本功能
这里使用了 python 的基本代码实现了 Linux 系统下 wc 命令程序的基本功能. #!/usr/bin/env python #encoding: utf-8 # Author: liwei ...
- strstr 函数的实现
strstr函数:返回主串中子字符串的位置后的所有字符. #include <stdio.h> const char *my_strstr(const char *str, const c ...
- [转]17个新手常见Python运行时错误
原址:http://www.oschina.net/question/89964_62779?p=1 当初学 Python 时,想要弄懂 Python 的错误信息的含义可能有点复杂.这里列出了常见的的 ...
- Java Generics and Collections-8.1
8.1 Take Care when Calling Legacy Code 通常,泛型都是在编译时检查的,而不是运行时.便意识检查可以提早通知错误,而不至于到运行时才出问题. 但有时后编译时检查不一 ...