UVA 1515 Pool construction 水塘(最大流,经典)
题意:
给一个h*w的矩阵,每个格子中是'#'和'.'两个符号之一,分别代表草和洞。现在要将洞给围起来(将草和洞分离),每条边需花费b元(即将一个洞包起来需要4边,将2个连续的洞包起来需要6边,省了2条边)。有个特殊能力,能将洞变成草,花费f。当然也能将草变成洞,花费d。围起洞来需要多少花费。矩阵四周最边边的格子都必须是草,即出现洞就必须转草。
转换:洞--->草--->洞
f d (元/格)
围洞: b元/边。
思路:
如果能够尽量让洞都靠在一起,那肯定是最小花费,因为少了很多条边。但是转换并不是免费,如果太贵,还不如不转,直接围。
这很像用一条绳子将洞给围起来,然后量绳子的周长。如果将格子看成点,那么就很像一个'割'(即将点分成两个集合)。问题是如何建模?
可以这么想,假设草上面都是水,自然就会流进洞里面,那么相邻的如果是草跟洞,则这条边就会有流通过,容量最多是b(相当于绳子的一部分)。这样子每个相邻的格子都需要建2条边互指(当然需要反向边),容量都是b,使得水可以流向洞中,花费就是流量。如果此时跑一次最大流(得加源汇点),就相当于求出不作'草洞'转换的围洞花费了。
但是问题是可以转来转去,如果草转洞很便宜,则应多转成洞。这样就需要协调了。水往低处流。我们在源点S到所有边边的草格子建立1条边,容量INF,接着,S连到所有其他的草格子,容量为d。其他的洞格子连到汇点T,容量为f。还有,每个格子和相邻的格子都有2条边,容量是b。新图就建完了,但是为什么这么做?
如下图,9个格子,4个草格子(边边被去掉):
. . .
.#.
###
明显,d比较小时,红色那块应该转洞,3段变1段花费。多小合适?d+b<3b时就合适,因为转的费用d,加上流进该新洞的流b,比原来需要3b要少。我们所设的(S-红草)这条边的容量是d,当满流时,也会从'红草'流向3个方向的洞中去,由红草流出的最大流不超过3b。此时,红草下的黑草,设为黑草A,它最多有b的流量可以流到红草喔,但是没办法,红草能承担的上限也只能是3b。若(S-红草)的流量>0,相当于帮忙减小了红草的压力,红草此时只是承受了来自S的d流量,还有黑草A的流量b而已。这样流来流去,红草流出的上限为3b,但是如果S给红草的d太小,即使加上黑草A的b,也是到达不了上限3b的,那么自动就被限流了。这个模型自动就被限流了,好像自动帮我们选择了“最省钱的方式”。同理,(洞-T) 也是这样,流到草格子B的流量欲超过f的话,还不如直接转成草,限流f就相当于自动转成草,如果少于f则相当于不转。
#include <bits/stdc++.h>
#define LL long long
#define pii pair<int,int>
#define INF 0x7f7f7f7f
using namespace std;
const int N=;
char g[][];
vector<int> vect[N];
struct node
{
int from, to, cap, flow;
node(){};
node(int a,int b,int c,int d):from(a), to(b), cap(c), flow(d){};
}edge[N*]; int edge_cnt;
void add_node(int a,int b,int c,int d)
{
edge[edge_cnt]=node(a,b,c,d);
vect[a].push_back(edge_cnt++);
} bool isOk(int x,int y,int h,int w){return x>&&x<=h&&y>&&y<=w? : ;}//判断是否在矩阵内 void build_graph(int h, int w,int b, int d,int f)//建图。
{
for(int i=; i<=h; i++)
{
for(int j=; j<=w; j++)
{
if( isOk(i, j-, h, w) ) //左边
{
add_node((i-)*w+j-, (i-)*w+j, b, );
add_node((i-)*w+j, (i-)*w+j-, , );
}
if( isOk(i, j+ ,h, w) ) //右边
{
add_node((i-)*w+j+, (i-)*w+j, b, );
add_node((i-)*w+j, (i-)*w+j+, , );
}
if( isOk(i-, j, h, w) ) //上边
{
add_node((i-)*w+j, (i-)*w+j, b, );
add_node((i-)*w+j, (i-)*w+j, , );
}
if( isOk(i+,j, h, w) ) //下边
{
add_node((i-)*w+j, i*w+j, b, );
add_node(i*w+j, (i-)*w+j, , );
} }
} for(int i=; i<=h; i++)
{
for(int j=; j<=w; j++)
{
if(i==||i==h || j==||j==w) //边边的草
{
add_node(, (i-)*w+j, INF, );
add_node((i-)*w+j, , , );
}
else if(g[i][j]=='#') //源点-草
{
add_node(, (i-)*w+j, d, );
add_node((i-)*w+j, , , );
}
else //洞-汇点
{
add_node((i-)*w+j, w*h+, f, );
add_node(w*h+, (i-)*w+j, , );
}
}
}
} int flow[N], path[N]; int BFS(int s,int e)
{
deque<int> que(,s);
flow[s]=INF;
while(!que.empty())
{
int x=que.front();
que.pop_front();
for(int i=; i<vect[x].size(); i++)
{
node e=edge[vect[x][i]];
if(!flow[e.to]&&e.cap>e.flow)
{
path[e.to]=vect[x][i];
flow[e.to]=min(flow[e.from], e.cap-e.flow);
que.push_back(e.to);
}
}
if(flow[e]) break;;
}
return flow[e];
} int max_flow(int s,int e)
{
int ans_flow=;
while(true)
{
memset(flow,,sizeof(flow));
memset(path,,sizeof(path)); int tmp=BFS(s, e);
if(tmp==) return ans_flow;
ans_flow+=tmp; int ed=e;
while(ed!=s)
{
int t=path[ed];
edge[t].flow+=tmp;
edge[t^].flow-=tmp;
ed=edge[t].from;
}
}
} int main()
{
freopen("input.txt", "r", stdin);
int t, w, h, d, f, b;
char c;
cin>>t;
while(t--)
{
scanf("%d%d %d%d%d", &w, &h, &d, &f,&b);
edge_cnt=;
memset(edge,,sizeof(edge));
for(int i=N-; i>=; i--) vect[i].clear(); for(int i=; i<=h; i++)
{
for(int j=; j<=w; j++)
{
c=getchar();
if(c=='#'||c=='.') g[i][j]=c;
else j--;
}
}
int ans=;
//处理掉四周:洞转草花费f元/格
for(int i=; i<=w; i++) if(g[][i]!='#') ans+=f; //第一行
for(int i=; i<=w; i++) if(g[h][i]!='#') ans+=f; //最后一行
for(int i=; i<h; i++) if(g[i][]!='#') ans+=f;
for(int i=; i<h; i++) if(g[i][w]!='#') ans+=f;
build_graph(h, w, b, d, f);
printf("%d\n",max_flow(, w*h+)+ans);
}
return ;
}
AC代码
UVA 1515 Pool construction 水塘(最大流,经典)的更多相关文章
- UVA 1515 Pool construction 最大流跑最小割
Pool construction You are working for the International Company for Pool Construction, a constructio ...
- UVa 1515 - Pool construction(最小割)
链接: https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem& ...
- Uva -1515 Pool construction(最小割)
输入一个字符矩阵,'.'代表洞,'#'代表草地.可以把草改成洞花费为d,或者把洞改成草花费为f,最后还要在草和洞之间修围栏花费为b. 首先把最外一圈的洞变成草,并累加花费. 增加一个源点和一个汇点,源 ...
- UVa1515 Pool construction(最小割)
题目 Source https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_pr ...
- poj--1149--PIGS(最大流经典建图)
PIGS Time Limit: 1000MS Memory Limit: 10000KB 64bit IO Format: %I64d & %I64u Submit Status D ...
- UVa 1515 (最小割) Pool construction
题意: 输入一个字符矩阵,'.'代表洞,'#'代表草地.可以把草改成洞花费为d,或者把洞改成草花费为f,最后还要在草和洞之间修围栏花费为b. 但要保证最外一圈是草,求最小费用. 分析: 还不是特别理解 ...
- 【uva 1515】Pool construction(图论--网络流最小割 模型题)
题意:有一个水塘,要求把它用围栏围起来,每个费用为b.其中,(#)代表草,(.)代表洞,把一个草变成洞需要费用d, 把一个洞变成草需要费用f.请输出合法方案中的最小费用. 解法:(不好理解...... ...
- [网络流最大流经典][uva 11082][矩阵解压]
题目大意 分析 #include <cstdio> #include <cstdlib> #include <cmath> #include <cstring ...
- UVA 10720 Graph Construction 贪心+优先队列
题目链接: 题目 Graph Construction Time limit: 3.000 seconds 问题描述 Graph is a collection of edges E and vert ...
随机推荐
- java 中的异常处理
一. 异常的概念和Java异常体系结构 异常是程序运行过程中出现的错误.本文主要讲授的是Java语言的异常处理.Java语言的异常处理框架, 是Java语言健壮性的一个重要体现. Java把 ...
- poj 3518 Corporate Identity 后缀数组->多字符串最长相同连续子串
题目链接 题意:输入N(2 <= N <= 4000)个长度不超过200的字符串,输出字典序最小的最长公共连续子串; 思路:将所有的字符串中间加上分隔符,注:分隔符只需要和输入的字符不同, ...
- 实现Linux select IO复用C/S服务器代码
已在ubuntu 下验证可用 服务器端 #include<stdio.h>#include<unistd.h>#include<stdlib.h>#include& ...
- 【BZOJ 1013】 [JSOI2008]球形空间产生器sphere
Description 有一个球形空间产生器能够在n维空间中产生一个坚硬的球体.现在,你被困在了这个n维球体中,你只知道球面上n+1个点的坐标,你需要以最快的速度确定这个n维球体的球心坐标,以便于摧毁 ...
- iOS 支付宝应用(备用参考2)
接入前期准备工作包括商户签约和密钥配置 步骤1: 启动IDE(如Xcode),把iOS包中的压缩文件中以下文件拷贝到项目文件夹下, 并导入到项目工程中. AlipaySDK.bundle Al ...
- 给QT不规则窗口添加阴影
在家休息,试着用QT去模仿各类管家软件的界面,做到自绘阴影的时候,蛋疼了. 网上搜到的基本都是一篇文章转来转去,一开始也被思路限制了. 尝试重载paintEvent,然后自己绘制矩形阴影,但是绘制的算 ...
- 【斜率DP】BZOJ 1010:玩具装箱
1010: [HNOI2008]玩具装箱toy Time Limit: 1 Sec Memory Limit: 162 MBSubmit: 7537 Solved: 2888[Submit][St ...
- rsync介绍
老套的搬用一下rsync的介绍,rsync是Linux系统下的数据镜像备份工具,从软件的命名上就可以看出来了——remote sync.rsync支持大多数的类Unix系统,无论是Linux.Sola ...
- ****JFinal 部署在 Tomcat 下推荐方法
首先明确一下 JFinal 项目是标准的 java web 项目,其部署方式与普通 java web 项目没有任何差别.Java Web 项目在 Tomcat 下部署有一些不必要的坑需要避免 经常有人 ...
- ***用php的strpos() 函数判断字符串中是否包含某字符串的方法
判断某字符串中是否包含某字符串的方法 if(strpos('www.idc-gz.com','idc-gz') !== false){ echo '包含'; }else{ echo '不包含'; } ...