题目

现在有一大块土地,可以看成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. Spring框架结构

    在processOn思维导图上看的一个程序员写的,挺不错的,分享出来,便于学习和回顾.

  2. 【BZOJ3230】相似子串 后缀数组+二分+RMQ

    [BZOJ3230]相似子串 Description Input 输入第1行,包含3个整数N,Q.Q代表询问组数.第2行是字符串S.接下来Q行,每行两个整数i和j.(1≤i≤j). Output 输出 ...

  3. SpringMVC结合REST

    一.什么是REST REST即 Representational State Transfer,也就是(资源)表现层状态转化.资源是指网络上的一个实体或者说是网络上的一个具体信息. 每种资源对应一个特 ...

  4. 九度OJ 1355:扑克牌顺子 (模拟)

    时间限制:2 秒 内存限制:32 兆 特殊判题:否 提交:1676 解决:484 题目描述: LL今天心情特别好,因为他去买了一副扑克牌,发现里面居然有2个大王,2个小王(一副牌原本是54张^_^). ...

  5. UnicodeEncodeError: 'latin-1' codec can't encode characters in position 0-3: ordinal not in range(256)

    今天使用MySQLdb往MySQL插入中文数据遇到一个异常: UnicodeEncodeError: 'latin-1' codec can't encode characters in positi ...

  6. world embedding 嵌入

    http://papers.nips.cc/paper/5477-neural-word-embedding-as-implicit-matrix-factorization 嵌入  |  Tenso ...

  7. OOP中的逆变和协变

    逆变和协变在存在于强类型语言中,尽管非常少提及.可是里面蕴含了面向对象的世界观.感谢和我一起讨论这个问题的人. 这里用了C#.Scala的语法作为演示样例.事实上逆变和协变的概念跟语言本身关系不大.事 ...

  8. cmd - - - 随笔

    dxdiag DirectX诊断工具 calc 计算机 cmd里面不想一点点输入冗长的文件路径?直接把这个文件拖到CMD窗口吧!你会发现 路径自己补上去了.有空格的还会自动加引号哟.

  9. window.location.assign和window.location.href区别

    window.location.assign和window.location.href区别 window.location.assign(url)和window.location.href=url实现 ...

  10. linux系统的nobody用户

    正如window系统在安装完毕后会自动建立一些用户账号,linux也会生成一些目标是为了完成特定任务的账号,如nobody和ftp 首先,nobody是一个普通用户,没有特权,他存在的目的是为了让任何 ...