题意:

  给一个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则相当于不转。

  1. #include <bits/stdc++.h>
  2. #define LL long long
  3. #define pii pair<int,int>
  4. #define INF 0x7f7f7f7f
  5. using namespace std;
  6. const int N=;
  7. char g[][];
  8. vector<int> vect[N];
  9. struct node
  10. {
  11. int from, to, cap, flow;
  12. node(){};
  13. node(int a,int b,int c,int d):from(a), to(b), cap(c), flow(d){};
  14. }edge[N*];
  15.  
  16. int edge_cnt;
  17. void add_node(int a,int b,int c,int d)
  18. {
  19. edge[edge_cnt]=node(a,b,c,d);
  20. vect[a].push_back(edge_cnt++);
  21. }
  22.  
  23. bool isOk(int x,int y,int h,int w){return x>&&x<=h&&y>&&y<=w? : ;}//判断是否在矩阵内
  24.  
  25. void build_graph(int h, int w,int b, int d,int f)//建图。
  26. {
  27. for(int i=; i<=h; i++)
  28. {
  29. for(int j=; j<=w; j++)
  30. {
  31. if( isOk(i, j-, h, w) ) //左边
  32. {
  33. add_node((i-)*w+j-, (i-)*w+j, b, );
  34. add_node((i-)*w+j, (i-)*w+j-, , );
  35. }
  36. if( isOk(i, j+ ,h, w) ) //右边
  37. {
  38. add_node((i-)*w+j+, (i-)*w+j, b, );
  39. add_node((i-)*w+j, (i-)*w+j+, , );
  40. }
  41. if( isOk(i-, j, h, w) ) //上边
  42. {
  43. add_node((i-)*w+j, (i-)*w+j, b, );
  44. add_node((i-)*w+j, (i-)*w+j, , );
  45. }
  46. if( isOk(i+,j, h, w) ) //下边
  47. {
  48. add_node((i-)*w+j, i*w+j, b, );
  49. add_node(i*w+j, (i-)*w+j, , );
  50. }
  51.  
  52. }
  53. }
  54.  
  55. for(int i=; i<=h; i++)
  56. {
  57. for(int j=; j<=w; j++)
  58. {
  59. if(i==||i==h || j==||j==w) //边边的草
  60. {
  61. add_node(, (i-)*w+j, INF, );
  62. add_node((i-)*w+j, , , );
  63. }
  64. else if(g[i][j]=='#') //源点-草
  65. {
  66. add_node(, (i-)*w+j, d, );
  67. add_node((i-)*w+j, , , );
  68. }
  69. else //洞-汇点
  70. {
  71. add_node((i-)*w+j, w*h+, f, );
  72. add_node(w*h+, (i-)*w+j, , );
  73. }
  74. }
  75. }
  76. }
  77.  
  78. int flow[N], path[N];
  79.  
  80. int BFS(int s,int e)
  81. {
  82. deque<int> que(,s);
  83. flow[s]=INF;
  84. while(!que.empty())
  85. {
  86. int x=que.front();
  87. que.pop_front();
  88. for(int i=; i<vect[x].size(); i++)
  89. {
  90. node e=edge[vect[x][i]];
  91. if(!flow[e.to]&&e.cap>e.flow)
  92. {
  93. path[e.to]=vect[x][i];
  94. flow[e.to]=min(flow[e.from], e.cap-e.flow);
  95. que.push_back(e.to);
  96. }
  97. }
  98. if(flow[e]) break;;
  99. }
  100. return flow[e];
  101. }
  102.  
  103. int max_flow(int s,int e)
  104. {
  105. int ans_flow=;
  106. while(true)
  107. {
  108. memset(flow,,sizeof(flow));
  109. memset(path,,sizeof(path));
  110.  
  111. int tmp=BFS(s, e);
  112. if(tmp==) return ans_flow;
  113. ans_flow+=tmp;
  114.  
  115. int ed=e;
  116. while(ed!=s)
  117. {
  118. int t=path[ed];
  119. edge[t].flow+=tmp;
  120. edge[t^].flow-=tmp;
  121. ed=edge[t].from;
  122. }
  123. }
  124. }
  125.  
  126. int main()
  127. {
  128. freopen("input.txt", "r", stdin);
  129. int t, w, h, d, f, b;
  130. char c;
  131. cin>>t;
  132. while(t--)
  133. {
  134. scanf("%d%d %d%d%d", &w, &h, &d, &f,&b);
  135. edge_cnt=;
  136. memset(edge,,sizeof(edge));
  137. for(int i=N-; i>=; i--) vect[i].clear();
  138.  
  139. for(int i=; i<=h; i++)
  140. {
  141. for(int j=; j<=w; j++)
  142. {
  143. c=getchar();
  144. if(c=='#'||c=='.') g[i][j]=c;
  145. else j--;
  146. }
  147. }
  148. int ans=;
  149. //处理掉四周:洞转草花费f元/格
  150. for(int i=; i<=w; i++) if(g[][i]!='#') ans+=f; //第一行
  151. for(int i=; i<=w; i++) if(g[h][i]!='#') ans+=f; //最后一行
  152. for(int i=; i<h; i++) if(g[i][]!='#') ans+=f;
  153. for(int i=; i<h; i++) if(g[i][w]!='#') ans+=f;
  154. build_graph(h, w, b, d, f);
  155. printf("%d\n",max_flow(, w*h+)+ans);
  156. }
  157. return ;
  158. }

AC代码

UVA 1515 Pool construction 水塘(最大流,经典)的更多相关文章

  1. UVA 1515 Pool construction 最大流跑最小割

    Pool construction You are working for the International Company for Pool Construction, a constructio ...

  2. UVa 1515 - Pool construction(最小割)

    链接: https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem& ...

  3. Uva -1515 Pool construction(最小割)

    输入一个字符矩阵,'.'代表洞,'#'代表草地.可以把草改成洞花费为d,或者把洞改成草花费为f,最后还要在草和洞之间修围栏花费为b. 首先把最外一圈的洞变成草,并累加花费. 增加一个源点和一个汇点,源 ...

  4. UVa1515 Pool construction(最小割)

    题目 Source https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_pr ...

  5. poj--1149--PIGS(最大流经典建图)

    PIGS Time Limit: 1000MS   Memory Limit: 10000KB   64bit IO Format: %I64d & %I64u Submit Status D ...

  6. UVa 1515 (最小割) Pool construction

    题意: 输入一个字符矩阵,'.'代表洞,'#'代表草地.可以把草改成洞花费为d,或者把洞改成草花费为f,最后还要在草和洞之间修围栏花费为b. 但要保证最外一圈是草,求最小费用. 分析: 还不是特别理解 ...

  7. 【uva 1515】Pool construction(图论--网络流最小割 模型题)

    题意:有一个水塘,要求把它用围栏围起来,每个费用为b.其中,(#)代表草,(.)代表洞,把一个草变成洞需要费用d, 把一个洞变成草需要费用f.请输出合法方案中的最小费用. 解法:(不好理解...... ...

  8. [网络流最大流经典][uva 11082][矩阵解压]

    题目大意 分析 #include <cstdio> #include <cstdlib> #include <cmath> #include <cstring ...

  9. UVA 10720 Graph Construction 贪心+优先队列

    题目链接: 题目 Graph Construction Time limit: 3.000 seconds 问题描述 Graph is a collection of edges E and vert ...

随机推荐

  1. 2014年辛星完全解读Javascript第四节 流程控制语句

    上一节我们介绍了函数,本小节我们介绍一下流程控制语句,对于任何一门编程语言来说,流程控制都是非常重要的,也就是我们常说的顺序结构.选择结构和循环结构. ************选择结构******** ...

  2. HDFS知识体系 思维导图

  3. 关于对db_block_gets的理解与实验

    实验 一. 自己手动创建的小表 创建一个区大小为  40k  SYS@ORCL>show parameter db_block_size NAME                         ...

  4. IOS平台汉字转拼音方案

    iOS/Mac OS X 汉字转拼音 网络流行的汉字转拼音方案是带一个拼音码表,速度快.其实Core Foundation也提供了一种方案,而且还带声调! NSMutableString *ms =  ...

  5. EXTJS4.2 控件之Grid 根据数据源某列数据不同绑定不同的控件setEditor

    Grid 根据数据源某列数据不同绑定不同的控件,例如:文本框和下拉框 主要代码写在grid的  plugins: [rowEditing],下面这是定义的rowEditing对象,这里面的要定义成 E ...

  6. LocalStorage 本地存储

    首先自然是检测浏览器是否支持本地存储.在HTML5中,本地存储是一个window的属性,包括localStorage和sessionStorage,从名字应该可以很清楚的辨认二者的区别,前者是一直存在 ...

  7. 浅谈Javascript 数组与字典

    Javascript 的数组Array,既是一个数组,也是一个字典(Dictionary). 先举例看看数组的用法. var a = new Array();  a[0] = "Acer&q ...

  8. LNMP笔记:更改网站文件和MySQL数据库的存放目录

    配置好LNMP环境以后,默认的网站目录和数据库存放目录都在系统盘,所以我们需要将它们转移到数据盘. 更改网站文件目录 如果你使用的是军哥的lnmp一键安装包,那默认的虚拟主机配置环境在 /usr/lo ...

  9. IDS 日志分析

    [http://blog.csdn.net/cnbird2008/article/details/5792626] General Approach通用方法1. Identify which log ...

  10. Google Play市场考察报告

    考察了Google Play日本市场的10款应用,考察的重点在于每个App有什么亮点,盈利模式在哪里.本文并不是App的功能介绍. (1)恋爱文集[文库类应用] 该应用收录了一些恋爱文章,其主要受众是 ...