[cqoi2012]交换棋子
2668: [cqoi2012]交换棋子
Time Limit: 3 Sec Memory Limit: 128 MB
Submit: 1334 Solved: 518
[Submit][Status][Discuss]
Description
Input
Output
Sample Input
110
000
001
000
110
100
222
222
222
Sample Output
HINT
Source
费用流,建图神建图。。。
照例说建图,看上去貌似毫无头绪,然而实际上还是可做的,首先可以看到有一个步数上限,自然就往网络流那边想,然后求最小交换的步数,应该貌似看上去是求一个最小费用,所以费用流。
首先自然是要拆点,比较特殊的是,这个题一个点拆三个点。。。。我们分别叫他们x,y,z,首先先从源点向所有是一的y点连一条容量为1,免费的边,从y点向汇点也这么连。然后对于这两张图,如果第一张图中有棋子,那么就连v[i][j]/2从x到y,(v[i][j]+1)/2从y到z,如果只是第二张图里有,那么就换换加一。最后把所有能互相影响的点从z到x连无限流0费的边,一遍费用流即可。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#define ll long long
#define inf 500000000
#define re register
#define id ((i-1)*m+j)
using namespace std;
struct po
{
int from,to,dis,nxt,w;
}edge[];
int head[],dep[],n,m,s,t,u,num=-,x,y,l,tot,sum,k,fa[];
int dis[],b[],xb[],flow[];
char map1[][],map2[][],mapn[][],cnt;
int dx[]={,-,-,-,,,,,};
int dy[]={,-,,,,,,-,-};
inline long long read()
{
long long x=,c=;
char ch=' ';
while((ch<''||ch>'')&&ch!='-')ch=getchar();
while(ch=='-')c*=-,ch=getchar();
while(ch>=''&&ch<='')x=x*+ch-'',ch=getchar();
return x*c;
}
inline void add_edge(int from,int to,int w,int dis)
{
edge[++num].nxt=head[from];
edge[num].to=to;
edge[num].w=w;
edge[num].dis=dis;
head[from]=num;
}
inline void add(int from,int to,int w,int dis)
{
add_edge(from,to,w,dis);
add_edge(to,from,,-dis);
}
inline bool spfa()
{
memset(b,,sizeof(b));
for(re int i=;i<=t;i++)
dis[i]=inf;
deque<int> q;
b[t]=;dis[t]=;
q.push_back(t);
while(!q.empty())
{
int u=q.front();
q.pop_front();
b[u]=;
for(re int i=head[u];i!=-;i=edge[i].nxt)
{
int v=edge[i].to;
if(edge[i^].w>&&dis[v]>dis[u]-edge[i].dis)
{
dis[v]=dis[u]-edge[i].dis;
if(!b[v])
{
b[v]=;
if(!q.empty()&&dis[v]>dis[q.front()])
q.push_front(v);
else
q.push_back(v);
}
}
}
}
return dis[s]<inf;
}
inline int dfs(int u,int low)
{
if(u==t)
{
b[t]=;
return low;
}
int diss=;
b[u]=;
for(re int i=head[u];i!=-;i=edge[i].nxt)
{
int v=edge[i].to;
if(!b[v]&&edge[i].w!=&&dis[v]==dis[u]-edge[i].dis)
{
int check=dfs(v,min(low,edge[i].w));
if(check>)
{
tot+=check*edge[i].dis;
low-=check;
diss+=check;
edge[i].w-=check;
edge[i^].w+=check;
if(low==) break;
}
}
}
return diss;
}
inline int max_flow()
{
int ans=;
while(spfa())
{
b[t]=;
while(b[t])
{
memset(b,,sizeof(b));
ans+=dfs(s,inf);
}
}
return ans;
}
int main()
{
memset(head,-,sizeof(head));
n=read();m=read();
s=;t=n*m*+;
int N=n*m;
for(re int i=;i<=n;i++)
for(re int j=;j<=m;j++){
cin>>map1[i][j];
if(map1[i][j]=='') add(s,id+N,,),cnt++;
}
for(re int i=;i<=n;i++)
for(re int j=;j<=m;j++){
cin>>map2[i][j];
if(map2[i][j]=='') add(id+N,t,,);
}
for(re int i=;i<=n;i++)
for(re int j=;j<=m;j++)
cin>>mapn[i][j];
for(re int i=;i<=n;i++)
for(re int j=;j<=m;j++){
if(map1[i][j]==map2[i][j]==''){
add(id,id+N,(mapn[i][j]-'')/,);add(id+N,id+N+N,(mapn[i][j]-'')/,);
}else if(map1[i][j]==''){
add(id,id+N,(mapn[i][j]-'')/,);add(id+N,id+N+N,(mapn[i][j]+-'')/,);
}else if(map2[i][j]==''){
add(id,id+N,(mapn[i][j]+-'')/,);add(id+N,id+N+N,(mapn[i][j]-'')/,);
}else add(id,id+N,(mapn[i][j]-'')/,),add(id+N,id+N+N,(mapn[i][j]-'')/,);
for(re int k=;k<=;k++){
int lx=dx[k]+i; int ly=dy[k]+j;
if(lx>=&&lx<=n&&ly>=&&ly<=m){
add(id+N+N,(lx-)*m+ly,inf,);
}
}
}
sum=max_flow();
if(sum>=cnt) cout<<tot;
else cout<<"-1";
}
[cqoi2012]交换棋子的更多相关文章
- BZOJ2668: [cqoi2012]交换棋子
题解: 可以戳这里:http://www.cnblogs.com/zig-zag/archive/2013/04/21/3033485.html 其实自己yy一下就知道这样建图的正确性了. 感觉太神奇 ...
- BZOJ 2668: [cqoi2012]交换棋子
2668: [cqoi2012]交换棋子 Time Limit: 3 Sec Memory Limit: 128 MBSubmit: 1112 Solved: 409[Submit][Status ...
- 【BZOJ2668】[cqoi2012]交换棋子 费用流
[BZOJ2668][cqoi2012]交换棋子 Description 有一个n行m列的黑白棋盘,你每次可以交换两个相邻格子(相邻是指有公共边或公共顶点)中的棋子,最终达到目标状态.要求第i行第j列 ...
- 洛谷 P3159(BZOJ 2668)[CQOI2012]交换棋子
有一个\(n\)行\(m\)列的黑白棋盘,你每次可以交换两个相邻格子(相邻是指有公共边或公共顶点)中的棋子,最终达到目标状态.要求第\(i\)行第\(j\)列的格子只能参与\(m[i][j]\)次交换 ...
- P3159 [CQOI2012]交换棋子
思路 相当神奇的费用流拆点模型 最开始我想到把交换黑色棋子看成一个流流动的过程,流从一个节点流向另一个节点就是交换两个节点,然后把一个位置拆成两个点限制流量,然后就有了这样的建图方法 S向所有初始是黑 ...
- BZOJ.2668.[CQOI2012]交换棋子(费用流zkw)
题目链接 首先黑白棋子的交换等价于黑棋子在白格子图上移动,都到达指定位置. 在这假设我们知道这题用网络流做. 那么黑棋到指定位置就是一条路径,考虑怎么用流模拟出这条路径. 我们发现除了路径的起点和终点 ...
- 2668: [cqoi2012]交换棋子
Description 有一个n行m列的黑白棋盘,你每次可以交换两个相邻格子(相邻是指有公共边或公共顶点)中的棋子,最终达到目标状态.要求第i行第j列的格子只能参与mi,j次交换. Input 第一行 ...
- [CQOI2012]交换棋子 网络流
---题面--- 题解: 一开始很快想出了一个接近正解的建图方法,但其实是错误的,不过还是骗了70分_(:зゝ∠)_ 首先我们可以观察到棋子有限,但费用多种,其实也就相当于限制了流量,找最小费用 对于 ...
- BZOJ2668:[CQOI2012]交换棋子——题解
http://www.lydsy.com/JudgeOnline/problem.php?id=2668 https://www.luogu.org/problemnew/show/P3159#sub ...
随机推荐
- go语言调用cmd
package main import ( "fmt" "os/exec" ) func main() { //删除C:\Users\Administrator ...
- OKhttp3
针对上一博文订单调用用户使用默认数据交互方式,下面介绍下使用 Okhttp3网络数据交换方式. 1.订单启动类变化 package com.tycoon.orderService; import or ...
- UVALive 5873 (几何+思维)
唉 被秀了... 还是太弱,说好的数形结合呢,列个式子出来后就被吓到了,然后就懵逼了. 题意: 有一条狗,从原点出发,沿n个向量走,每个向量只走一次,沿着一个向量(x,y)走时,既可以往(x,y)方向 ...
- docker学习笔记(2) 构建镜像
一.手动构建一个简单镜像 我们以构建nginx的docker镜像为例:手动构建镜像 docker pull centos 安装基础镜像docker run --name mynginx -it ...
- 【BZOJ3043】IncDec Sequence 乱搞
[BZOJ3043]IncDec Sequence Description 给定一个长度为n的数列{a1,a2...an},每次可以选择一个区间[l,r],使这个区间内的数都加一或者都减一.问至少需要 ...
- 从网上搜索到的一些关于pcap源代码,入门级的
/*pcap_1.c*/ #include <stdio.h>#include <stdlib.h>#include <pcap.h> /* 如果没有pcap的系 ...
- 记录-Jquery uploadify文件上传实例
原本做的是from表单的文件上传,后来因需要用ajax异步,so接触到了Jquery uploadify上传 贴上代码,以供参考 需要引入的js文件 <link href="../re ...
- 多进程端口监听 How nginx processes a request Server names
网络编程( 六):端口那些事儿 - 知乎专栏 https://zhuanlan.zhihu.com/p/20365900 不停服务reload.restart 多进程端口监听 我们都有一个计算机网络 ...
- 【转】图解MySql命令行创建存储过程
一 操作实例 首先登录mysql: 使用source命令,从命令行执行sql脚本,创建表: 创建第一个存储过程: 事先用DELIMITER关键字申明当前段分隔符,这样MySQL才会将";&q ...
- Wireshark网络分析工具(二)
一.TCP三次握手过称 1. 第一次握手的数据包 客户端发送一个TCP,标志位为SYN,序列号为0, 代表客户端请求建立连接. 如下图: 2. 第二次握手的数据包 服务器发回确认包, 标志位为 SYN ...