bzoj 4261: 建设游乐场 费用流
题目
现在有一大块土地,可以看成N*M的方格。在这块土地上,有些格子内是崎岖的山地,无法建造任何东西;其他格子都是平原。现在打算在这块土地上建设一个游乐园。游乐园由若干条闭合的过山车轨道组成,每个平原格子都要铺一截轨道,为下列 6 种类型中的一种:
(每张图表示一块平原格子,图内网格线为辅助线,无实际意义。)
其中前 2 种为直轨道,后 4 种为弯轨道。显然对游客来说,弯轨道更加刺激。
由于每块格子风景各不相同,经过一番研究,现给了N*M个方格中的每个格子一个评估值,意义为:如果该格子修建弯轨道,会给游客们带来多少的愉悦值。现需要一名设计师,帮他设计一种最优的轨道建设方案,使所有格子给游客们带来的愉悦值之和尽量大。(如果没有合法方案,输出 -1)
N<=150,M<=30,Vi,j<=100
题解:
乍一看没有什么思路.
但仔细观察一下可以通过直觉感觉出来是网络流。
(OI人的直觉)
在棋盘问题上应用网络流算法,经典的就是黑白染色。
所以我们将棋盘黑白染色。
然后我们考虑怎样构造方案:
- 一定有每个黑色格子与两个白色格子连接且每个白色格子与两个黑色各自连接.
如果能达到这个,那么一定可行.
所以可以用最大流来判断是否可行.

其中每个加粗边的流量是2,然后我们判断一下最大流是否为节点数即可.
那么对于转弯时付出的代价要怎么计算?
我们还是在上述的模型中进行改进,我们对边赋以权值。
然后考虑把点拆成和x方向的白点进行连接与和y方向的白点进行连接两种点。
然后再加一个点来控制到达这两个点的总流量为2。
然后就很明朗了,我们只要完成这么一个限制:如果流量分别走了两边,就获得权值。
... ...
但是经过仔细思考后并不能完成这么一个限制...
所以考虑转化一下。我们知道上述条件等价于:如果流量都走了同一边,就无法获得权值.
这个限制是我们可以简单完成的,只要利用凸费用流的性质即可.
所以跑最小费用最大流即可.
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
inline void read(int &x){
x=0;char ch;bool flag = false;
while(ch=getchar(),ch<'!');if(ch == '-') ch=getchar(),flag = true;
while(x=10*x+ch-'0',ch=getchar(),ch>'!');if(flag) x=-x;
}
#define rg register int
#define rep(i,a,b) for(rg i=(a);i<=(b);++i)
#define per(i,a,b) for(rg i=(a);i>=(b);--i)
const int maxn = 160;
const int maxm = 36;
const int maxnode = 3*maxn*maxm;
const int maxedge = maxnode*4;
struct Edge{
int to,next,cost,cap;
}G[maxedge<<1];
int head[maxnode],cnt = 1;
inline void add(int u,int v,int c,int d){
G[++cnt].to = v;
G[cnt].next = head[u];
G[cnt].cap = c;
G[cnt].cost = d;
head[u] = cnt;
}
inline void insert(int u,int v,int c,int d){
add(u,v,c,d);add(v,u,0,-d);
}
#define v G[i].to
const int lim = maxnode<<1;
int q[lim+10],dis[maxnode],p[maxnode];
int flow[maxnode];
int l,r,S,T,fl;ll ans;bool inq[maxnode];
int nodecnt;
const int inf = 0x3f3f3f3f;
inline bool spfa(){
rep(i,1,nodecnt){
dis[i] = inf;
inq[i] = false;
}
l = 0;r = -1;q[++r % lim] = S;
inq[S] = true;flow[S] = inf;
dis[S] = 0;
while(l <= r){
int u = q[l++ % lim];
for(rg i = head[u];i;i=G[i].next){
if(dis[v] > dis[u] + G[i].cost && G[i].cap > 0){
dis[v] = dis[u] + G[i].cost;
flow[v] = min(flow[u],G[i].cap);
p[v] = i;
if(!inq[v]){
q[++r % lim] = v;
inq[v] = true;
}
}
}inq[u] = false;
}if(dis[T] == inf) return false;
ans += 1LL*flow[T]*dis[T];
fl += flow[T];
for(rg u = T;u != S;u = G[p[u]^1].to)
G[p[u]].cap -= flow[T],G[p[u]^1].cap += flow[T];
return true;
}
#undef v
int idx[maxn][maxm],idy[maxn][maxm],id[maxn][maxm];
int main(){
int n,m;read(n);read(m);
int x,num = 0;
rep(i,1,n){
rep(j,1,m){
read(x);
if(x == 0){
++ num;
id[i][j] = ++ nodecnt;
idx[i][j] = ++ nodecnt;
idy[i][j] = ++ nodecnt;
}
}
}
ll tot = 0;
S = ++ nodecnt;T = ++ nodecnt;
rep(i,1,n){
rep(j,1,m){
read(x);
if(id[i][j] == 0) continue;
tot += x;
if((i+j)&1^1){
insert(S,id[i][j],2,0);
insert(id[i][j],idx[i][j],1,0);
insert(id[i][j],idx[i][j],1,x);
insert(id[i][j],idy[i][j],1,0);
insert(id[i][j],idy[i][j],1,x);
}else{
insert(id[i][j],T,2,0);
insert(idx[i][j],id[i][j],1,0);
insert(idx[i][j],id[i][j],1,x);
insert(idy[i][j],id[i][j],1,0);
insert(idy[i][j],id[i][j],1,x);
}
if((i+j)&1^1){
int x,y;
x = i-1;y = j;
if(1<=x && x<=n && 1<=y && y<=m && id[x][y]) insert(idx[i][j],idx[x][y],1,0);
x = i+1;y = j;
if(1<=x && x<=n && 1<=y && y<=m && id[x][y]) insert(idx[i][j],idx[x][y],1,0);
x = i;y = j-1;
if(1<=x && x<=n && 1<=y && y<=m && id[x][y]) insert(idy[i][j],idy[x][y],1,0);
x = i;y = j+1;
if(1<=x && x<=n && 1<=y && y<=m && id[x][y]) insert(idy[i][j],idy[x][y],1,0);
}
}
}
while(spfa());
if(fl != nodecnt / 3){
puts("-1");
return 0;
}
printf("%lld\n",tot - ans);
return 0;
}
bzoj 4261: 建设游乐场 费用流的更多相关文章
- BZOJ 4261: 建设游乐场
4261: 建设游乐场 Time Limit: 50 Sec Memory Limit: 256 MBSubmit: 38 Solved: 16[Submit][Status][Discuss] ...
- [bzoj 1449] 球队收益(费用流)
[bzoj 1449] 球队收益(费用流) Description Input Output 一个整数表示联盟里所有球队收益之和的最小值. Sample Input 3 3 1 0 2 1 1 1 1 ...
- BZOJ.2597.[WC2007]剪刀石头布(费用流zkw)
BZOJ 洛谷 \(Description\) 给定一张部分边方向已确定的竞赛图.你需要给剩下的边确定方向,使得图中的三元环数量最多. \(n\leq100\). \(Solution\) 这种选择之 ...
- bzoj 1070: [SCOI2007]修车 费用流
1070: [SCOI2007]修车 Time Limit: 1 Sec Memory Limit: 162 MBSubmit: 2785 Solved: 1110[Submit][Status] ...
- BZOJ 3171 循环格(费用流)
题意 一个循环格就是一个矩阵,其中所有元素为箭头,指向相邻四个格子.每个元素有一个坐标(行,列),其中左上角元素坐标为(0,0).给定一个起始位置(r,c),你可以沿着箭头防线在格子间行走.即如果(r ...
- BZOJ 1070 修车 【费用流】
Description 同一时刻有N位车主带着他们的爱车来到了汽车维修中心.维修中心共有M位技术人员,不同的技术人员对不同 的车进行维修所用的时间是不同的.现在需要安排这M位技术人员所维修的车及顺序, ...
- BZOJ 1930 吃豆豆(费用流)
首先这题的两条线不相交的限制可以去掉,因为如果相交的话把点换一换是不影响最终结果的. 剩下的费用流建图是显然的,把点拆为两个,建立超级源点s和源点ss汇点t,连边(s,ss,2,0). 对于每个点,连 ...
- BZOJ 1927 星际竞速(费用流)
考虑费用流,题目要求走n个点都走完且恰好一次,显然流量的限制为n. 建立源点s和汇点t,并把每个星球拆成两个点i和i',分别表示已到达该点和经过该点. 对于能力爆发,建边(s,i',1,w). 对应高 ...
- BZOJ 1221 软件开发(费用流)
容易看出这是显然的费用流模型. 把每天需要的餐巾数作为限制.需要将天数拆点,x’表示每天需要的餐巾,x’’表示每天用完的餐巾.所以加边 (s,x',INF,0),(x'',t,INF,0). 餐巾可以 ...
随机推荐
- Excel中批量把数字类型转换为文本类型
客户给的excel文件中的内容全部是数值类型,这些我们要当成文本存入到数据库,所以需要把所有的数值转换为文本,但是直接通过修改单元格属性来修改的话会变成科学技数法,还有一种方法是在数值得前面加个英文的 ...
- 【BZOJ3744】Gty的妹子序列 分块+树状数组
[BZOJ3744]Gty的妹子序列 Description 我早已习惯你不在身边, 人间四月天 寂寞断了弦. 回望身后蓝天, 跟再见说再见…… 某天,蒟蒻Autumn发现了从 Gty的妹子树(bzo ...
- WCF基础之序列化
wcf是基于消息进行通信的,这篇就是简单说下序列化引擎是如何将.net object转化为xml消息.一般情况下很少用到这些,你只需定义数据协定之类的或者指定相应的序列化引擎,然后设置相应的特性就好. ...
- php解析xml文件为数组
$xml = simplexml_load_file($fullfilename); $arr = json_decode(json_encode($xml),true); echo "&l ...
- ZOJ - 3537 Cake (凸包+区间DP+最优三角剖分)
Description You want to hold a party. Here's a polygon-shaped cake on the table. You'd like to cut t ...
- centos安装 Falcon+
1:环境 准备 : 安装 go环境 :下载 - Golang中国 参照 :http://www.cnblogs.com/Amos-Turing/p/8494250.html 安装 mysql 安装 r ...
- python webserver客户端
1.库 suds库,只能做webserver客户端,轻量化,使用方便.安装使用pip. 2.使用 如有webserver情况如下: url:http://10.110.35.41:8980/wsser ...
- mybatis中查询结果进行分组
在用mybatis进行数据库查询时,对查询结果进行自动分组,在mapper.xml中的配置有些注意的地方,下面是实际项目中一个例子.在数据库中查询中如下: 在结果集中需要对alarmDate进行分组, ...
- MyBatis:学习笔记(4)——动态SQL
MyBatis:学习笔记(4)——动态SQL 如果使用JDBC或者其他框架,很多时候需要你根据需求手动拼装SQL语句,这是一件非常麻烦的事情.MyBatis提供了对SQL语句动态的组装能力,而且他只有 ...
- Vue:实践学习笔记(1)——快速使用
Vue:实践学习笔记(1)——快速使用 Vue基础知识 0.引入Vue 官方地址:Vue的官方下载地址 Vue推荐博客:keepfool 在你的程序中快速引入Vue: <!-- 开发环境版本,包 ...
