题目

现在有一大块土地,可以看成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: 建设游乐场 费用流的更多相关文章

  1. BZOJ 4261: 建设游乐场

    4261: 建设游乐场 Time Limit: 50 Sec  Memory Limit: 256 MBSubmit: 38  Solved: 16[Submit][Status][Discuss] ...

  2. [bzoj 1449] 球队收益(费用流)

    [bzoj 1449] 球队收益(费用流) Description Input Output 一个整数表示联盟里所有球队收益之和的最小值. Sample Input 3 3 1 0 2 1 1 1 1 ...

  3. BZOJ.2597.[WC2007]剪刀石头布(费用流zkw)

    BZOJ 洛谷 \(Description\) 给定一张部分边方向已确定的竞赛图.你需要给剩下的边确定方向,使得图中的三元环数量最多. \(n\leq100\). \(Solution\) 这种选择之 ...

  4. bzoj 1070: [SCOI2007]修车 费用流

    1070: [SCOI2007]修车 Time Limit: 1 Sec  Memory Limit: 162 MBSubmit: 2785  Solved: 1110[Submit][Status] ...

  5. BZOJ 3171 循环格(费用流)

    题意 一个循环格就是一个矩阵,其中所有元素为箭头,指向相邻四个格子.每个元素有一个坐标(行,列),其中左上角元素坐标为(0,0).给定一个起始位置(r,c),你可以沿着箭头防线在格子间行走.即如果(r ...

  6. BZOJ 1070 修车 【费用流】

    Description 同一时刻有N位车主带着他们的爱车来到了汽车维修中心.维修中心共有M位技术人员,不同的技术人员对不同 的车进行维修所用的时间是不同的.现在需要安排这M位技术人员所维修的车及顺序, ...

  7. BZOJ 1930 吃豆豆(费用流)

    首先这题的两条线不相交的限制可以去掉,因为如果相交的话把点换一换是不影响最终结果的. 剩下的费用流建图是显然的,把点拆为两个,建立超级源点s和源点ss汇点t,连边(s,ss,2,0). 对于每个点,连 ...

  8. BZOJ 1927 星际竞速(费用流)

    考虑费用流,题目要求走n个点都走完且恰好一次,显然流量的限制为n. 建立源点s和汇点t,并把每个星球拆成两个点i和i',分别表示已到达该点和经过该点. 对于能力爆发,建边(s,i',1,w). 对应高 ...

  9. BZOJ 1221 软件开发(费用流)

    容易看出这是显然的费用流模型. 把每天需要的餐巾数作为限制.需要将天数拆点,x’表示每天需要的餐巾,x’’表示每天用完的餐巾.所以加边 (s,x',INF,0),(x'',t,INF,0). 餐巾可以 ...

随机推荐

  1. python 上传文件下载图片

    python 2.7 poster-0.8.1 requests-2.7.0 #coding:utf-8import urllibimport urllib2import sysimport time ...

  2. spring bean的scope

    scope用来声明容器中的对象所应该处的限定场景或者说该对象的存活时间,即容器在对象进入其相应的scope之前,生成并装配这些对象,在该对象不再处于这些scope的限定之后,容器通常会销毁这些对象. ...

  3. 关于function的一种常用用法

    关于function的一种常用用法 void Share::InitAcrossManager() { GsMgrEvent gsMgrEvents;//保存function的结构体 gsMgrEve ...

  4. 浅谈公平组合游戏IGC

    浅谈公平组合游戏IGC IGC简介 一个游戏满足以下条件时被叫做IGC游戏 (前面三个字是自己YY的,不必在意) 竞争性:两名玩家交替行动. 公平性:游戏进程的任意时刻,可以执行的操作和操作者本人无关 ...

  5. shell if判断-n

    test测试命令 test命令用于检查某个条件是否成立,它可以进行数值.字符串和文件三个方面的测试,其测试符和相应的功能分别如下: (1)数值测试: -eq:等于则为真        -ne:不等于则 ...

  6. log4j2.xml的例子

    项目中用到的一个log4j2.xml的配置文件: <?xml version="1.0" encoding="UTF-8"?> <!--设置l ...

  7. DEV开发之界面皮肤

    最终效果:正文本人的环境是 VS2013+DEV 13.21.第一步,新建项目,(忽略)???2.修改Form1.cs的基类,Form修改为DevExpress.XtraBars.Ribbon.Rib ...

  8. 纯CSS3实现关闭按钮

    在线演示 本地下载

  9. Spring Cloud之Feign客户端调用工具

    feign介绍 Feign客户端是一个web声明式http远程调用工具,提供了接口和注解方式进行调用. Spring Cloud 支持 RestTemplate  Fetin Feign客户端实际开发 ...

  10. MySql-rules

    1.mySql基础 USE day15; -- 创建表 CREATE TABLE teacher( id INT, NAME VARCHAR() ) -- 查看所有表 SHOW TABLES; DES ...