题意: 一个数字矩阵,可以出发K次,每次可以从右边或者下面走,要求(在收益最大情况下)覆盖全图,不能则输出-1。(规则:每次跳一步的时候若格子数字相等则获得该数字的能量,每跳一步消耗距离的能量)。每个格子走且仅能走一次。

选<=K条路径,最优情况来覆盖全图。

显然用拆点为二分图。

一种解法:边(流量,费用)

源点向X部连边(1,0)Y部向汇点连边(1,0)X到Y,若能到,则有边(1,消耗-获得)。关键点(解决每个点都覆盖,恰好起到填补的作用):在X部最上面添加一个点,源点连之(k,0)它向所有Y点连边(1,0)。跑最小费用最大流即可。

第二种:(感想zz1215提供的建图思路)

源点向X部连边(1,0)Y部向汇点连边(1,0),Y到X,若能到,则有边(1,消耗-获得)(注意这里是回流),每个点I-->I`有边(1,-w_inf),这里的w_inf为相对大数,只要保证该费用较“小”即可(相对其他费用,他是最廉价的,这样必优先流这条边。添加超级源点,向源点连边(K,0)。增广K次中,若一直增大,则取最大,否则到开始下降的时候要BREAK。(先曾后减的)。

PS:开始时候因为定位编号搞错有没有!编号(i,j)=i*m+j,而不是i*n+j!!!

图:

代码:

  1. #include<iostream> //24ms
  2. #include<cstdio>
  3. #include<algorithm>
  4. #include<queue>
  5. #include<string>
  6. using namespace std;
  7. int n,m,k;
  8. const int inf=0x3f3f3f3f;
  9. int a[25][25];
  10. int head[500];int e[10000][4];int nume=0;
  11. void inline adde(int i,int j,int c,int w)
  12. {
  13. e[nume][0]=j;e[nume][1]=head[i];head[i]=nume;
  14. e[nume][2]=c;e[nume++][3]=w;
  15. e[nume][0]=i;e[nume][1]=head[j];head[j]=nume;
  16. e[nume][2]=0;e[nume++][3]=-w;
  17. }
  18. int inq[500];int d[500];
  19. bool spfa(int &sumcost)
  20. {
  21. for(int i=0;i<=2*n*m+3;i++)
  22. {
  23. inq[i]=0;d[i]=inf;
  24. }
  25. int minf=inf;
  26. queue<int>q;
  27. int prv[300];int pre[300];
  28. q.push(2*n*m+2);
  29. inq[2*n*m+2]=1;
  30. d[2*n*m+2]=0;
  31. while(!q.empty())
  32. {
  33. int cur=q.front();
  34. q.pop();inq[cur]=0;
  35. for(int i=head[cur];i!=-1;i=e[i][1])
  36. {
  37. int v=e[i][0];
  38. if(e[i][2]>0&&d[v]>e[i][3]+d[cur])
  39. {
  40. d[v]=e[i][3]+d[cur];
  41. prv[v]=cur;
  42. pre[v]=i;
  43. if(!inq[v])
  44. {
  45. q.push(v);
  46. inq[v]=1;
  47. }
  48. }
  49. }
  50. }
  51. if(d[2*n*m+1]==inf)return 0;
  52. int cur=2*n*m+1;
  53. while(cur!=2*n*m+2)
  54. {
  55. minf=min(minf,e[pre[cur]][2]);
  56. cur=prv[cur];
  57. }
  58. cur=2*n*m+1;
  59. while(cur!=2*n*m+2)
  60. {
  61. e[pre[cur]][2]-=minf;e[pre[cur]^1][2]+=minf;
  62. cur=prv[cur];
  63. }
  64. sumcost+=d[2*n*m+1]*minf;
  65. return 1;
  66. }
  67. int mincost()
  68. {
  69. int sum=0;
  70. while(spfa(sum));
  71. return sum;
  72. }
  73. void init()
  74. {
  75. nume=0;
  76. for(int i=0;i<=2*n*m+3;i++)
  77. {
  78. head[i]=-1;
  79. }
  80. }
  81. int main()
  82. {
  83. int T;
  84. scanf("%d",&T);
  85. for(int iii=1;iii<=T;iii++)
  86. {
  87. scanf("%d%d%d",&n,&m,&k);
  88. init();
  89. string s;
  90. for(int i=0;i<n;i++)
  91. {
  92. cin>>s;
  93. for(int j=0;j<m;j++)
  94. {
  95. a[i][j]=s[j]-'0';
  96. }
  97. }
  98. printf("Case %d : ",iii);
  99.  
  100. if(min(n,m)>k)
  101. {
  102. printf("-1\n");continue;
  103. }
  104. for(int i=0;i<n;i++) //起点2*n*m+2,终点2*n*m+1
  105. for(int j=0;j<m;j++)
  106. {
  107. for(int ii=i+1;ii<n;ii++)
  108. {
  109. int temp=(a[i][j]==a[ii][j]?a[i][j]:0);
  110. adde(m*i+j,m*ii+j+n*m+1,1,ii-i-1-temp);
  111. }
  112.  
  113. for(int jj=j+1;jj<m;jj++)
  114. {
  115. int temp=(a[i][j]==a[i][jj]?a[i][j]:0);
  116. adde(m*i+j,m*i+jj+n*m+1,1,jj-j-1-temp);
  117. }
  118. }
  119. for(int i=0;i<n*m;i++)
  120. adde(2*n*m+2,i,1,0);
  121. adde(2*n*m+2,n*m,k,0);
  122. for(int i=n*m+1;i<=2*n*m;i++)
  123. {
  124. adde(n*m,i,1,0);
  125. adde(i,2*n*m+1,1,0);
  126. }
  127. /* for(int i=0;i<=2*n*m+2;i++)
  128. for(int j=head[i];j!=-1;j=e[j][1])
  129. printf("%d->%d:c:%d,w:%d\n",i,e[j][0],e[j][2],e[j][3]);*/
  130. printf("%d\n",-mincost());
  131. }
  132. return 0;
  133. }

方法二:

  1. #include<iostream> //31ms
  2. #include<cstdio>
  3. #include<queue>
  4. #include<string>
  5. using namespace std;
  6. int n,m,k;
  7. const int inf=0x3f3f3f3f;
  8. const int winf=100000;
  9. int a[25][25];
  10. int head[500];int e[20001][4];int nume=0;
  11. void inline adde(int i,int j,int c,int w)
  12. {
  13. e[nume][0]=j;e[nume][1]=head[i];head[i]=nume;
  14. e[nume][2]=c;e[nume++][3]=w;
  15. e[nume][0]=i;e[nume][1]=head[j];head[j]=nume;
  16. e[nume][2]=0;e[nume++][3]=-w;
  17. }
  18. int inq[500];int d[500];
  19. bool spfa(long long &sumcost)
  20. {
  21. for(int i=0;i<=2*n*m+3;i++)
  22. {
  23. inq[i]=0;d[i]=inf;
  24. }
  25. int prv[500];int pre[500];
  26. int minf=inf;
  27. queue<int>q;
  28. q.push(n*m);
  29. inq[n*m]=1;
  30. d[n*m]=0;
  31. while(!q.empty())
  32. {
  33. int cur=q.front();
  34. q.pop();
  35. inq[cur]=0;
  36. for(int i=head[cur];i!=-1;i=e[i][1])
  37. {
  38. int v=e[i][0];
  39. if(e[i][2]>0&&d[v]>e[i][3]+d[cur])
  40. {
  41. d[v]=e[i][3]+d[cur];
  42. prv[v]=cur;
  43. pre[v]=i;
  44. if(!inq[v])
  45. {
  46. q.push(v);
  47. inq[v]=1;
  48. }
  49. }
  50. }
  51. }
  52. if(d[2*n*m+1]==inf)return 0;
  53. int cur=2*n*m+1;
  54. while(cur!=n*m)
  55. {
  56. minf=min(minf,e[pre[cur]][2]);
  57. cur=prv[cur];
  58. }
  59. cur=2*n*m+1;
  60. while(cur!=n*m)
  61. {
  62. e[pre[cur]][2]-=minf;
  63. e[pre[cur]^1][2]+=minf;
  64. cur=prv[cur];
  65. }
  66. sumcost+=d[2*n*m+1]*(long long)minf;
  67. return 1;
  68. }
  69. long long mincost()
  70. {
  71. long long sum=0;
  72. long long lastsum=0;
  73. while(spfa(sum)) //变小的时候跳出
  74. {
  75. if(lastsum>=-sum){return -lastsum;}
  76. lastsum=-sum;
  77. }
  78. return sum;
  79. }
  80. void init()
  81. {
  82. nume=0;
  83. for(int i=0;i<=2*n*m+3;i++)
  84. {
  85. head[i]=-1;
  86. }
  87. }
  88. int main()
  89. {
  90. int T;
  91. scanf("%d",&T);
  92. for(int iii=1;iii<=T;iii++)
  93. {
  94. scanf("%d%d%d",&n,&m,&k);
  95. init();
  96. string s;
  97. for(int i=0;i<n;i++)
  98. {
  99. cin>>s;
  100. for(int j=0;j<m;j++)
  101. {
  102. a[i][j]=s[j]-'0';
  103. }
  104. }
  105. printf("Case %d : ",iii);
  106.  
  107. if(min(n,m)>k)
  108. {
  109. printf("-1\n");continue;
  110. }
  111. for(int i=0;i<n;i++) //起点n*m,终点:2*n*m+1
  112. for(int j=0;j<m;j++)
  113. {
  114. for(int ii=i+1;ii<n;ii++)
  115. {
  116. int temp=(a[i][j]==a[ii][j]?a[i][j]:0);
  117. adde(m*i+j+n*m+1,m*ii+j,1,ii-i-1-temp);
  118. }
  119. for(int jj=j+1;jj<m;jj++)
  120. {
  121. int temp=(a[i][j]==a[i][jj]?a[i][j]:0);
  122. adde(m*i+j+n*m+1,m*i+jj,1,jj-j-1-temp);
  123. }
  124. }
  125. for(int i=0;i<n*m;i++)
  126. adde(2*n*m+2,i,1,0);
  127. adde(n*m,n*m*2+2,k,0);
  128. for(int i=n*m+1;i<=2*n*m;i++)
  129. {
  130. adde(i-n*m-1,i,1,-winf);
  131. adde(i,2*n*m+1,1,0);
  132. }
  133. /* for(int i=0;i<=2*n*m+2;i++)
  134. for(int j=head[i];j!=-1;j=e[j][1])
  135. printf("%d->%d:c:%d,w:%d\n",i,e[j][0],e[j][2],e[j][3]);*/
  136. cout<<-mincost()-n*m*winf<<endl;
  137. }
  138. return 0;
  139. }

hdu4862 2014多校B题/ 费用流(最优情况下用不大于K条路径覆盖)(不同的解法)的更多相关文章

  1. 【思维题 费用流 技巧】bzoj5403: marshland

    主要还是网络流拆点建图一类技巧吧 Description JudgeOnline/upload/201806/1(4).pdf 题目分析 第一眼看到这题时候只会把每个点拆成4个方向:再强制定向连边防止 ...

  2. 补 第三场多校杭电 费用流 K Subsequence

    K Subsequence 这个题目是这个人想吃东西,但是他每次吃的都是他的美味值都必须不递减,可以吃k次,问这个最大的美味值是多少. 这个是一个比较明显的费用流,建图也很好建,但是呢,这个题目卡sp ...

  3. CFGYM 2013-2014 CT S01E03 D题 费用流模版题

    题意: n行, a房间的气球,b房间的气球 i行需要的气球,与a房的距离,b房的距离 求最小距离 #include <stdio.h> #include <string.h> ...

  4. BZOJ.2324.[ZJOI2011]营救皮卡丘(费用流 Floyd)

    BZOJ 洛谷 首先预处理出\(dis[i][j]\),表示从\(i\)到\(j\)的最短路.可以用\(Floyd\)处理. 注意\(i,j\)是没有大小关系限制的(\(i>j\)的\(dis[ ...

  5. BZOJ2324 ZJOI2011营救皮卡丘(floyd+上下界费用流)

    虽然不一定每次都是由编号小的点向编号大的走,但一个人摧毁的顺序一定是从编号小的到编号大的.那么在摧毁据点x的过程中,其只能经过编号小于x的点.并且这样一定合法,因为可以控制其他人先去摧毁所经过的点.那 ...

  6. hdu4862 费用流(不错)

    题意:       给你一个矩阵,你最多可以选择k条路线,k条路线的起点随意,每次行走的距离随意,但是只能往右或者下走,走过的点不能再走,而且每一步如果a->b,如果a和b的权值s相等那么就可以 ...

  7. 【BZOJ3130】费用流(最大流,二分)

    [BZOJ3130]费用流(最大流,二分) 题面 Description Alice和Bob在图论课程上学习了最大流和最小费用最大流的相关知识. 最大流问题:给定一张有向图表示运输网络,一个源点S和一 ...

  8. 【BZOJ2324】[ZJOI2011]营救皮卡丘(网络流,费用流)

    [BZOJ2324][ZJOI2011]营救皮卡丘(网络流,费用流) 题面 BZOJ 洛谷 题解 如果考虑每个人走的路径,就会很麻烦. 转过来考虑每个人破坏的点集,这样子每个人可以得到一个上升的序列. ...

  9. [费用流][BZOJ1070]修车

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

随机推荐

  1. 47.Number of Islands(岛的数量)

    Level:   Medium 题目描述: Given a 2d grid map of '1's (land) and '0's (water), count the number of islan ...

  2. RLock(递归锁)

    import threading, time def run1(): print("grab the first part data") lock.acquire()#进入大门后的 ...

  3. 分享一个Delphi跨平台Http库的封装,一个Delphi跨平台TCP库的封装

    { 单元名:跨平台的TCP客户端库封装 作者:5bug 网站:http://www.5bug.wang } unit uCPTcpClient; interface uses System.Class ...

  4. Windows MinGW 64-bit boost 踩坑

    >g++ -Wall -shared -g -DBUILD_DLL main.cpp -ID:\gcc\boost\include\boost-1_69 -LD:\gcc\boost\lib - ...

  5. springmvc导出excel(POI)

    /** * 导出excel表格 */ @RequestMapping(value = "/doExportData", method = {RequestMethod.POST, ...

  6. iOS 面试集锦2

    4.写一个setter方法用于完成@property (nonatomic,retain)NSString *name,写一个setter方法用于完成@property(nonatomic,copy) ...

  7. CentOS 7 升级gcc/g++编译器

    gcc的升级必须要使用源码进行升级,也就说,必须要使用源码进行编译才行.我的7.2的CentOS目前自带的gcc是4.8.5的,gcc从4.8之后开始支持C++11,但是鉴于现在C++14.C++17 ...

  8. linux uptime-查看Linux系统负载信息

    更多linux 性能监测与优化 关注:linux命令大全 uptime命令能够打印系统总共运行了多长时间和系统的平均负载.uptime命令可以显示的信息显示依次为:现在时间.系统已经运行了多长时间.目 ...

  9. RN原生的安卓UI组件

    https://facebook.github.io/react-native/docs/native-components-android.html 这里有一大堆的原生组件可以用,一些是平台自带的, ...

  10. Safari不能保存session的处理方法

    在vue单页应用项目中,safari浏览器验证码登陆提示'验证码过期'或者验证码校验不通过的问题 原因:验证码存储在了session里,接着验证时又发起了一次会话,因为Safari不保存cookie, ...