4261: 建设游乐场

Time Limit: 50 Sec  Memory Limit: 256 MB
Submit: 38  Solved: 16
[Submit][Status][Discuss]

Description

现在有一大块土地,可以看成N*M的方格。在这块土地上,有些格子内是崎岖的山地,无法建造任何东西;其他格子都是平原。现在打算在这块土地上建设一个游乐园。游乐园由若干条闭合的过山车轨道组成,每个平原格子都要铺一截轨道,为下列 6 种类型中的一种:
(每张图表示一块平原格子,图内网格线为辅助线,无实际意义。)
 
其中前 2 种为直轨道,后 4 种为弯轨道。显然对游客来说,弯轨道更加刺激。
 
由于每块格子风景各不相同,经过一番研究,现给了N*M个方格中的每个格子一个评估值,意义为:如果该格子修建弯轨道,会给游客们带来多少的愉悦值。现需要一名设计师,帮他设计一种最优的轨道建设方案,使所有格子给游客们带来的愉悦值之和尽量大。(如果没有合法方案,输出 -1)

Input

第一行两个正整数 n, m。
接下来 n 行,每行 m 个数,描述了整块土地。其中 1 表示山地,0 表示平原。接下来 n 行,每行 m 个非负整数,第 i 行第 j 个为 Vi,j,表示格子 (i,j) 修建弯轨道能给游客们带来的愉悦值。

Output

一行一个数,表示最优设计方案中给游客们带来的愉悦值之和。

Sample Input

3 3
1 1 1
1 0 0
1 0 0
48 94 1
78 78 81
1 12 60

Sample Output

231

HINT

N<=150,M<=30,Vi,j<=100

Source

分析:

好题~~~

考虑构成若干个环的必要条件:每个格子的管道都要链接相邻的两个格子...然后把一个格子拆成两个管子,如果两个管子方向不同,则可以得到价值,如果相同就无法得到...

既然是网格图,那么我们考虑黑白染色,对于每个必须放的格子,我们把这个格子拆成三个点,一个点叫做控制点,一个代表竖向管道,一个代表横向管道...

然后对于每个黑点,从$S$向黑点的控制点连边$<S,id[i][j][0],2,0>$,代表连接两个格子,$<id[i][j][0],id[i][j][1],1,val>$,$<id[i][j][0],id[i][j][1],id[i][j][2],1,val>$,$<id[i][j][0],id[i][j][1],1,0>$,$<id[i][j][0],id[i][j][2],1,0>$...

对于每个白点,从白点的控制点向$T$连边$<id[i][j][0],T,2,0>$,然后$1$、$2$的连边和黑点相反...

然后对于每个黑点,我们把竖向点向上下的相邻格子个竖点连边$<1,0>$,横向点向左右的横向点连边$<1,0>$...

这样,如果满流并且黑白点相同的话就一定是合法解,因为代表每个格子都连接了相邻的两个格子...然后如果一个各自选择了相同方向的管道,那么会得到$val$的收益,如果选择不同的,会得到$2*val$的收益,所以求出最大费用之后减去$\sum val$就好了...

代码:

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
//by NeighThorn
#define inf 0x3f3f3f3f
#define min(a,b) a>b?b:a
using namespace std; const int N=150+5,maxn=50000+5,maxm=1000000+5; int n,m,S,T,cnt,tat,tot,sum,mp[N][N],id[N][N][3],val[N][N];
int w[maxm],fl[maxm],hd[maxn],to[maxm],nxt[maxm],Min[maxn],dis[maxn],vis[maxn],from[maxn];
int mv[4][2]={1,0,-1,0,0,1,0,-1}; inline int read(void){
char ch=getchar();int x=0;
while(!(ch>='0'&&ch<='9')) ch=getchar();
while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
return x;
} inline void add(int x,int y,int l,int s){
w[cnt]= s;fl[cnt]=l;to[cnt]=y;nxt[cnt]=hd[x];hd[x]=cnt++;
w[cnt]=-s;fl[cnt]=0;to[cnt]=x;nxt[cnt]=hd[y];hd[y]=cnt++;
} inline bool spfa(void){
memset(Min,inf,sizeof(Min));
memset(dis,inf,sizeof(dis));
queue<int> q;q.push(S);dis[S]=0;vis[S]=1;
while(!q.empty()){
int top=q.front();q.pop();vis[top]=0;
for(int i=hd[top];i!=-1;i=nxt[i])
if(dis[to[i]]>dis[top]+w[i]&&fl[i]){
from[to[i]]=i;
dis[to[i]]=dis[top]+w[i];
Min[to[i]]=min(Min[top],fl[i]);
if(!vis[to[i]])
vis[to[i]]=1,q.push(to[i]);
}
}
return dis[T]!=inf;
} inline int find(void){
for(int i=T;i!=S;i=to[from[i]^1])
fl[from[i]]-=Min[T],fl[from[i]^1]+=Min[T];
return Min[T]*dis[T];
} inline int mcmf(void){
int res=0,flow=0;
while(spfa())
res+=find(),flow+=Min[T];
if(flow!=tot) return -1;
return -res-sum;
} signed main(void){
n=read();m=read();
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
mp[i][j]=read();
for(int i=0;i<=n+1;i++) mp[i][0]=mp[i][m+1]=1;
for(int i=0;i<=m+1;i++) mp[0][i]=mp[n+1][i]=1;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++){
val[i][j]=read();
if(!mp[i][j])
sum+=val[i][j];
}
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
if(!mp[i][j])
for(int k=0;k<3;k++)
id[i][j][k]=++tot;
S=0,T=++tot;tot=0;
memset(hd,-1,sizeof(hd));
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
if(!mp[i][j]){
if((i+j)&1)
tat+=2,
add(S,id[i][j][0],2,0),
add(id[i][j][0],id[i][j][1],1,0),
add(id[i][j][0],id[i][j][2],1,0),
add(id[i][j][0],id[i][j][1],1,-val[i][j]),
add(id[i][j][0],id[i][j][2],1,-val[i][j]);
else
tot+=2,
add(id[i][j][0],T,2,0),
add(id[i][j][1],id[i][j][0],1,0),
add(id[i][j][2],id[i][j][0],1,0),
add(id[i][j][1],id[i][j][0],1,-val[i][j]),
add(id[i][j][2],id[i][j][0],1,-val[i][j]);
}
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
if(!mp[i][j]&&((i+j)&1)){
for(int k=0,x,y;k<4;k++){
x=i+mv[k][0],y=j+mv[k][1];
if(!mp[x][y]){
if(k<2)
add(id[i][j][1],id[x][y][1],1,0);
else
add(id[i][j][2],id[x][y][2],1,0);
}
}
}
if(tat!=tot) return puts("-1"),0;
printf("%d\n",mcmf());
return 0;
}

  


By NeighThorn

BZOJ 4261: 建设游乐场的更多相关文章

  1. bzoj 4261: 建设游乐场 费用流

    题目 现在有一大块土地,可以看成N*M的方格.在这块土地上,有些格子内是崎岖的山地,无法建造任何东西:其他格子都是平原.现在打算在这块土地上建设一个游乐园.游乐园由若干条闭合的过山车轨道组成,每个平原 ...

  2. 【BZOJ-4261】建设游乐场 最大费用最大流

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

  3. BZOJ4261 : 建设游乐场

    将图黑白染色,每个点拆成两个点,分别表示水平和竖直方向,再增加一个点以控制流量,那么每个格子都需要找两个方向去连接. $S$到每个黑点的控制点连边,流量$2$,费用$0$: 控制点向两个方向的点各连两 ...

  4. bzoj AC倒序

    Search GO 说明:输入题号直接进入相应题目,如需搜索含数字的题目,请在关键词前加单引号 Problem ID Title Source AC Submit Y 1000 A+B Problem ...

  5. BZOJ 1096 【ZJOI2007】 仓库建设

    Description L公司有N个工厂,由高到底分布在一座山上.如图所示,工厂1在山顶,工厂N在山脚.由于这座山处于高原内陆地区(干燥少雨),L公司一般把产品直接堆放在露天,以节省费用.突然有一天, ...

  6. 【BZOJ 1096】 [ZJOI2007]仓库建设 (斜率优化)

    1096: [ZJOI2007]仓库建设 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 3940  Solved: 1736 Description ...

  7. bzoj 1096 仓库建设 -斜率优化

    L公司有N个工厂,由高到底分布在一座山上.如图所示,工厂1在山顶,工厂N在山脚.由于这座山处于高原内陆地区(干燥少雨),L公司一般把产品直接堆放在露天,以节省费用.突然有一天,L公司的总裁L先生接到气 ...

  8. 【BZOJ】1096: [ZJOI2007]仓库建设(dp+斜率优化)

    http://www.lydsy.com/JudgeOnline/problem.php?id=1096 首先得到dp方程(我竟然自己都每推出了QAQ)$$d[i]=min\{d[j]+cost(j+ ...

  9. BZOJ 2001: [Hnoi2010]City 城市建设

    2001: [Hnoi2010]City 城市建设 Time Limit: 20 Sec  Memory Limit: 162 MBSubmit: 1132  Solved: 555[Submit][ ...

随机推荐

  1. python__基础 : 类的继承,调用父类的属性和方法

    1.继承,调用父类属性方法 在python里面,继承一个类只需要这样写: class Animal: def heshui(self): print('动物正在喝水') class Cat(Anima ...

  2. POJ:3579-Median(二分+尺取寻找中位数)

    Median Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 9201 Accepted: 3209 Description Gi ...

  3. Json的用处一

    今天,我们用到了json的的用处,其实也就是一个很简单的用处,就是点击一个按钮,触发一个事件,然后调用json, 之后我们就可以进行异步操作,其实只是针对于后台的操作,其实我们并没有对数据库进行刷新, ...

  4. PHP.19-验证码生成

    生成验证码 思路:先定义验证码函数getCode() //绘制验证码 $num = 4; //字符长度 getCode($num, 2); 1.创建画布,分配颜色 imagecreatetruecol ...

  5. 9,Flask 中的蓝图(BluePrint)

    蓝图,听起来就是一个很宏伟的东西,在Flask中的蓝图 blueprint 也是非常宏伟的,它的作用就是将 功能 与 主服务 分开. 比如说,你有一个客户管理系统,最开始的时候,只有一个查看客户列表的 ...

  6. sql查询作业答案

    sql查询作业答案   阅读目录 一 题目 二 答案 一 题目 1.查询所有的课程的名称以及对应的任课老师姓名 2.查询学生表中男女生各有多少人 3.查询物理成绩等于100的学生的姓名 4.查询平均成 ...

  7. 直接插入排序&希尔排序

    1.直接插入排序 时间复杂度O(n2) 工作原理: 通过构建有序序列,对于未排序数据,在已排序的序列中,从后向前扫描,找到相应的位置并插入. 插入排序在实现上,在从后向前扫描的过程中,需要反复把已排序 ...

  8. centos使用--软件启动关闭等操作的命令

    关于centos服务的命令经常会遇到这几种 service systemctl /etc/init.d/ 1 service和/etc/init.d/ service是一个脚本命令,分析service ...

  9. Python基础——安装运行

    Python是如何运行的? 像绝大多数编程语言一样,要在计算机上能够运行python程序,至少需要安装一个最小的Python包:一个Python解释器和支持的库. 安装Python 安装包下载:htt ...

  10. Object Pascal中文手册 经典教程

    Object Pascal 参考手册 (Ver 0.1)ezdelphi@hotmail.com OverviewOverview(概述)Using object pascal(使用 object p ...