感受到网络流的强大了……这道题目的关键在于:

  前后颜色不变的,流入流出的次数相等;原本是黑色的最后变成了白色,流出比流入次数多1;原本是白色最后变成黑色,流入比流出次数多一。所以我们将每一点拆成3个点,分别代表流入点,原点与流出点。最开始为黑色的点与源点连流量为1,费用为0的边,最后为黑色的点与汇点连流量为1,费用为0的边。

#include<bits/stdc++.h>
using namespace std;
#define maxn 300
#define maxm 8000
#define INF 99999
int n, m, size, tem, a[maxn][maxn], b[maxn][maxn], c[maxn][maxn], head[maxm];
int cnp, fans, ans, cost, dis[maxm], pre[maxm], flow[maxm];
int dx[] = {, , , , , , -, -, -};
int dy[] = {, , -, , , -, , , -};
int s = , t;
bool vis[maxm];
deque <int> q; struct edge
{
int to, last, f, c;
}E[maxn * ]; void add(int u, int v, int f, int c)
{
E[cnp].to = v, E[cnp].last = head[u], E[cnp].f = f, E[cnp].c = c; head[u] = cnp ++;
E[cnp].to = u, E[cnp].last = head[v], E[cnp].f = , E[cnp].c = -c; head[v] = cnp ++;
} int Get_id(int x, int y)
{
return (x - ) * m + y;
} void init()
{
memset(head, -, sizeof(head));
} int SPFA()
{
q.push_back(s);
flow[s] = INF;
for(int i = ; i <= n * m * + ; i ++) dis[i] = INF;
while(!q.empty())
{
int u = q.front();
q.pop_front();
vis[u] = false;
for(int i = head[u]; i != -; i = E[i].last)
{
int v = E[i].to;
if(E[i].f && dis[v] > dis[u] + E[i].c)
{
dis[v] = dis[u] + E[i].c, pre[v] = i;
flow[v] = min(flow[u], E[i].f);
if(!vis[v])
{
vis[v] = true;
if(!q.empty() && dis[v] < dis[q.front()]) q.push_front(v);
else q.push_front(v);
}
}
}
}
if(dis[t] >= INF) return false;
else return true;
} void Max_flow()
{
while(SPFA())
{
int v = pre[t];
while()
{
E[v].f -= flow[t];
E[v ^ ].f += flow[t];
if(E[v ^ ].to == s) break;
v = pre[E[v ^ ].to];
}
ans += flow[t];
cost += flow[t] * dis[t];
}
} void Get_input()
{
for(int i = ; i <= n; i ++)
{
string s; cin >> s;
for(int j = ; j < m; j ++)
a[i][j + ] = s[j] - '';
}
for(int i = ; i <= n; i ++)
{
string s; cin >> s;
for(int j = ; j < m; j ++)
b[i][j + ] = s[j] - '';
}
for(int i = ; i <= n; i ++)
{
string s; cin >> s;
for(int j = ; j < m; j ++)
c[i][j + ] = s[j] - '';
}
} void Connect()
{
for(int i = ; i <= n; i ++)
for(int j = ; j <= m; j ++)
{
int u = Get_id(i, j);
if(a[i][j]) tem ++, add(s, u, , );
if(b[i][j]) fans ++, add(u, t, , );
if(a[i][j] == b[i][j])
{
add(u + size, u, c[i][j] / , );
add(u, u + * size, c[i][j] / , );
}
else if(b[i][j])
{
add(u + size, u, (c[i][j] + ) / , );
add(u, u + * size, c[i][j] / , );
}
else if(a[i][j])
{
add(u + size, u, c[i][j] / , );
add(u, u + * size, (c[i][j] + ) / , );
}
for(int k = ; k <= ; k ++)
{
int x = i + dx[k], y = j + dy[k];
if(x < || x > n || y < || y > m) continue;
add(u + * size, Get_id(x, y) + size, INF, );
}
}
} int main()
{
scanf("%d%d", &n, &m);
init();
t = n * m * + , size = n * m;
Get_input();
Connect();
if(tem != fans)
{
printf("-1\n");
return ;
}
Max_flow();
if(ans == fans) printf("%d", cost >> );
else printf("-1\n");
return ;
}

【题解】CQOI2012交换棋子的更多相关文章

  1. BZOJ2668: [cqoi2012]交换棋子

    题解: 可以戳这里:http://www.cnblogs.com/zig-zag/archive/2013/04/21/3033485.html 其实自己yy一下就知道这样建图的正确性了. 感觉太神奇 ...

  2. 【BZOJ2668】[cqoi2012]交换棋子 费用流

    [BZOJ2668][cqoi2012]交换棋子 Description 有一个n行m列的黑白棋盘,你每次可以交换两个相邻格子(相邻是指有公共边或公共顶点)中的棋子,最终达到目标状态.要求第i行第j列 ...

  3. BZOJ 2668: [cqoi2012]交换棋子

    2668: [cqoi2012]交换棋子 Time Limit: 3 Sec  Memory Limit: 128 MBSubmit: 1112  Solved: 409[Submit][Status ...

  4. [cqoi2012]交换棋子

      2668: [cqoi2012]交换棋子 Time Limit: 3 Sec  Memory Limit: 128 MBSubmit: 1334  Solved: 518[Submit][Stat ...

  5. BZOJ2668:[CQOI2012]交换棋子——题解

    http://www.lydsy.com/JudgeOnline/problem.php?id=2668 https://www.luogu.org/problemnew/show/P3159#sub ...

  6. 洛谷 P3159(BZOJ 2668)[CQOI2012]交换棋子

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

  7. [CQOI2012]交换棋子 网络流

    ---题面--- 题解: 一开始很快想出了一个接近正解的建图方法,但其实是错误的,不过还是骗了70分_(:зゝ∠)_ 首先我们可以观察到棋子有限,但费用多种,其实也就相当于限制了流量,找最小费用 对于 ...

  8. BZOJ2668:[CQOI2012]交换棋子(费用流)

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

  9. [luoguP3159] [CQOI2012]交换棋子(最小费用最大流)

    传送门 好难的网络流啊,建图真的超难. 如果不告诉我是网络流的话,我估计就会写dfs了. 使用费用流解决本题,设点 $p[i][j]$ 的参与交换的次数上限为 $v[i][j]$ ,以下为建图方式: ...

随机推荐

  1. ThinkPHP创建应用

    新建一个文件 引入ThinkPHP文件

  2. while else

    count = 0 while count <= 5 : count += 1 if count == 3:pass print("Loop",count) else: pr ...

  3. ruby $LOAD_PATH及类加载

    $LOAD_PATH $LOAD_PATH 指的是Ruby读取外部文件的一个环境变量,其实和windows的环境变量是一个概念.Ruby会在这个环境变量的路径中读取需要require的文件,如果在环境 ...

  4. vue 项目如何使用微信分享接口

    首先做微信网页都要接入微信sdk: 安装sdk npm install weixin-js-sdk --save 具体可以查看微信公众平台技术文档:https://mp.weixin.qq.com/w ...

  5. 开启一个项目如何上传到git

    1.(先进入项目文件夹)通过命令 git init 把这个目录变成git可以管理的仓库 git init 2.把文件添加到版本库中,使用命令 git add .添加到暂存区里面去,不要忘记后面的小数点 ...

  6. FireDAC 连接Access (accdb)数据库

    FireDAC可以方便连接数据库,但是要连接新版本的accdb数据库,要注意这样的事项(以Office2010版为例) 安装Office2010 x86版,注意,不能安装x64版,因为Delphi I ...

  7. Mysql双主操作

    MySQL双主(主主)架构方案   在企业中,数据库高可用一直是企业的重中之重,中小企业很多都是使用mysql主从方案,一主多从,读写分离等,但是单主存在单点故障,从库切换成主库需要作改动.因此,如果 ...

  8. Cadence17.2下载ALTERA的FPGA封装库

    1. 在Cadence的安装目录里面找了下,发现都没有Altera的FPGA型号的函数库,下面的虽然是ALTERA,但是没有FPGA的器件封装 2. 去intel的官网看能不能下载到,INTEL网址, ...

  9. Objective-C反射机制

    oc反射机制有三个用途: 1.获得Class Class LoginViewController = NSClassFromString(@"LoginViewController" ...

  10. 《.NET 微服务:适用于容器化 .NET 应用的体系结构》关键结论

    作为总结和要点,以下是本指南中最重要的结论.1 使用容器的好处: 基于容器的解决方案有节约成本的好处,因为容器是针对生产环境中缺少依赖而导致的部署问题提出的解决方案.容器能够显著改善devops和生产 ...