Gym101194J Mr.Panda and TubeMaster 二分图、费用流
看到这张图,是一个网格图,而且有回路限制,不难想到黑白染色。
一般来说我们对一张图黑白染色之后都是黑色点向白色点连边,但是这道题往这边想似乎就想不出建图方法了,因为“一个格子强制流满\(2\)的流”和“权值和最大”无法同时在这张图上体现出来。
实际上这道题黑色和白色、白色和黑色之间都需要连边。
我们令左右方向的管道全部从黑色向白色连,上下方向的管道全部从白色往黑色连。也就是对于每一个点拆成入点和出点,对于黑色的入点,向其左右方向的白色出点连边;对于白色的入点,向其上下方向的黑色出点连边。连边的容量为\(1\)、费用为管道的价值。
然后考虑强制选择的限制。对于某个点,如果它没有被强制限制,就将其入点和出点之间连一条容量为\(1\)、费用为\(0\)的边,表示它能够自己和自己匹配。
这样就可以跑最大费用最大流了。
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<ctime>
#include<cctype>
#include<algorithm>
#include<cstring>
#include<iomanip>
#include<queue>
#include<map>
#include<set>
#include<bitset>
#include<stack>
#include<vector>
#include<cmath>
#include<random>
#include<cassert>
#define INF 0x3f3f3f3f
//This code is written by Itst
using namespace std;
const int MAXN = 1e5 + 7 , MAXM = 1e6 + 7;
struct Edge{
int end , upEd , f , c;
}Ed[MAXM];
int head[MAXN] , val[32][32][2] , id[32][32][2];
int N , M , S , T , cntEd = 1;
bool mrk[32][32];
queue < int > q;
inline void addEd(int a , int b , int c , int d = 0){
Ed[++cntEd].end = b;
Ed[cntEd].upEd = head[a];
Ed[cntEd].f = c;
Ed[cntEd].c = d;
head[a] = cntEd;
}
inline void addE(int a , int b , int c , int d = 0 , bool f = 0){
addEd(a , b , c , d); addEd(b , a , c * f , -d);
}
bool vis[MAXN];
int dis[MAXN] , pre[MAXN] , flo[MAXN];
inline bool SPFA(){
memset(dis , -0x3f , sizeof(dis));
dis[S] = 0;
while(!q.empty())
q.pop();
q.push(S);
flo[S] = INF;
while(!q.empty()){
int t = q.front();
q.pop();
vis[t] = 0;
for(int i = head[t] ; i ; i = Ed[i].upEd)
if(Ed[i].f && dis[Ed[i].end] < dis[t] + Ed[i].c){
dis[Ed[i].end] = dis[t] + Ed[i].c;
flo[Ed[i].end] = min(Ed[i].f , flo[t]);
pre[Ed[i].end] = i;
if(!vis[Ed[i].end]){
vis[Ed[i].end] = 1;
q.push(Ed[i].end);
}
}
}
return dis[T] != dis[T + 1];
}
int EK(){
int ans = 0 , flow = 0;
while(SPFA()){
int cur = T , sum = 0;
while(cur != S){
sum += Ed[pre[cur]].c;
Ed[pre[cur]].f -= flo[T];
Ed[pre[cur] ^ 1].f += flo[T];
cur = Ed[pre[cur] ^ 1].end;
}
flow += flo[T];
ans += sum * flo[T];
}
return flow == N * M ? ans : -1;
}
int main(){
#ifndef ONLINE_JUDGE
freopen("in" , "r" , stdin);
//freopen("out" , "w" , stdout);
#endif
ios::sync_with_stdio(0);
int t , E , x , y , Case = 0;
for(cin >> t ; t ; --t){
cin >> N >> M;
T = 0; cntEd = 1;
memset(head , 0 , sizeof(head));
memset(mrk , 0 , sizeof(mrk));
for(int i = 1 ; i <= N ; ++i)
for(int j = 1 ; j <= M ; ++j){
id[i][j][0] = ++T; id[i][j][1] = ++T;
}
for(int i = 1 ; i <= N ; ++i)
for(int j = 1 ; j < M ; ++j){
cin >> x;
if(!((i + j) & 1)) val[i][j][1] = x;
else val[i][j + 1][0] = x;
}
for(int i = 1 ; i < N ; ++i)
for(int j = 1 ; j <= M ; ++j){
cin >> x;
if((i + j) & 1) val[i][j][1] = x;
else val[i + 1][j][0] = x;
}
++T;
for(cin >> E ; E ; --E){cin >> x >> y; mrk[x][y] = 1;}
for(int i = 1 ; i <= N ; ++i)
for(int j = 1 ; j <= M ; ++j){
addE(S , id[i][j][0] , 1);
addE(id[i][j][1] , T , 1);
if(!mrk[i][j]) addE(id[i][j][0] , id[i][j][1] , 1);
if((i + j) & 1){
if(i != 1)
addE(id[i][j][0] , id[i - 1][j][1] , 1 , val[i][j][0]);
if(i != N)
addE(id[i][j][0] , id[i + 1][j][1] , 1 , val[i][j][1]);
}
else{
if(j != 1)
addE(id[i][j][0] , id[i][j - 1][1] , 1 , val[i][j][0]);
if(j != M)
addE(id[i][j][0] , id[i][j + 1][1] , 1 , val[i][j][1]);
}
}
int t = EK();
cout << "Case #" << ++Case << ": ";
if(t == -1) cout << "Impossible\n";
else cout << t << '\n';
}
return 0;
}
Gym101194J Mr.Panda and TubeMaster 二分图、费用流的更多相关文章
- China Final J - Mr.Panda and TubeMaster
和一般的管道不同 不能类似“无限之环”或者“弯弯国”的建图,因为这两个题都是某些位置必须有,或者必须没有 但是本题可以有的位置随意,不能限制某个位置要么流2,要么流0,(实际上可能流了1过去) 所以建 ...
- ICPC 2016 China Final J. Mr.Panda and TubeMaster【最大费用最大流】
有一种限制下界强制选的,但是也可以不用 把每个格点拆成两个,一个连s一个连t,对于不是必选的连中间连流量1费用0边表示不选,然后黑白染色,黑点连横着白点连竖着,边权就是这条水管的权值,然后跑最大费用最 ...
- 【费用流】 ICPC 2016 China Final J. Mr.Panda and TubeMaster
表示“必须选”的模型 题目大意 题目分析 一个格子有四种方式看上去很难处理.将横竖两个方向分开考虑,会发现:因为收益只与相邻格子是否连通有关,所以可以将一个格子拆成表示横竖两个方向的,互相独立的点. ...
- J - Mr.Panda and TubeMaster
题解 我们可以把每个格子拆成两个点,一个表示横向的,一个表示纵向的,相邻的格子横向和纵向连边. 如果直接按照题意做的话,我们应当在横向和纵向的点之间连边,有限制的边设下界为1,然后跑可行流. 或者考虑 ...
- POJ2195 Going Home[费用流|二分图最大权匹配]
Going Home Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 22088 Accepted: 11155 Desc ...
- BZOJ.4514.[SDOI2016]数字配对(费用流SPFA 二分图)
BZOJ 洛谷 \(Solution\) 很显然的建二分图后跑最大费用流,但有个问题是一个数是只能用一次的,这样二分图两部分都有这个数. 那么就用两倍的.如果\(i\)可以向\(j'\)连边,\(j\ ...
- 【BZOJ 3308】 3308: 九月的咖啡店 (费用流|二分图最大权匹配)
3308: 九月的咖啡店 Time Limit: 30 Sec Memory Limit: 128 MBSubmit: 244 Solved: 86 Description 深绘里在九份开了一家咖 ...
- 【LA2238 训练指南】固定分区内存管理 【二分图最佳完美匹配,费用流】
题意 早期的多程序操作系统常把所有的可用内存划分为一些大小固定的区域,不同的区域一般大小不同,而所有区域的大小之和为可用内存的大小.给定一些程序,操作系统需要给每个程序分配一个区域,使得他们可以同时执 ...
- 【LA4043 训练指南】蚂蚁 【二分图最佳完美匹配,费用流】
题意 给出n个白点和n个黑点的坐标,要求用n条不相交的线段把他们连接起来,其中每条线段恰好连接一个白点和一个黑点,每个点恰好连接一条线段. 分析 结点分黑白,很容易想到二分图.其中每个白点对应一个X结 ...
随机推荐
- Java环境变量搭建
安装JDK开发环境 jdk下载地址:https://www.oracle.com/technetwork/java/javase/downloads/jdk10-downloads-4416644.h ...
- 自己动手写Android插件化框架,让老板对你刮目相看
欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~ 本文由达文西发表于云+社区专栏 最近在工作中接触到了Android插件内的开发,发现自己这种技术还缺乏最基本的了解,以至于在一些基本问题上浪 ...
- (后端)Spring手动回滚事务
百度上查资料获得的 throw new RuntimeException(); 或者 TransactionAspectSupport.currentTransactionStatus().setR ...
- spring学习总结——介绍
介绍:以下博客的内容都是依据<spring实战4>这本书.spring4.0 来总结. 一.spring作用 Spring可以做很多事情,它为企业级开发提供给了丰富的功能,但是这些功能的底 ...
- 智能ERP 交接班统计异常的解决方法
请注意,有交接班统计数据不准确的需开启离线统计即可解决,交接班统计是按照结账时间来进行统计的 1.点击左侧导航栏中‘更多’-进入系统设置 2.进入营业设置后-开启离线统计-点击保存
- 洗礼灵魂,修炼python(64)--爬虫篇—re模块/正则表达式(2)
前面学习了元家军以及其他的字符匹配方法,那得会用啊对吧?本篇博文就简单的解析怎么运用 正则表达式使用 前面说了正则表达式的知识点,本篇博文就是针对常用的正则表达式进行举例解析.相信你知道要用正则表达式 ...
- ASP.Net上传文件
在做Web项目时,上传文件是经常会碰到的需求.ASP.Net的WebForm开发模式中,封装了FileUpload控件,可以方便的进行文件上传操作.但有时,你可能不希望使用ASP.Net中的服务器控件 ...
- org.hibernate.NonUniqueObjectException
错误如下: 2017-3-29 15:17:52~ERROR~org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperV ...
- Linux atop 监控系统状态
atop是一个功能非常强大的linux服务器监控工具,它的数据采集主要包括:CPU.内存.磁盘.网络.进程等,并且内容非常的详细,特别是当那一部分存在压力它会以特殊的颜色进行展示,如果颜色是红色那么说 ...
- shell read变量的读入
shell变量的输入: shell变量除了可以直接赋值或脚本传参外,还可以使用read命令从标准输入获取,read为bash内置命令,可以通过help read查看帮助. 语法格式: read [参数 ...