HOJ 2715 Matrix3

限制增广次数的费用流。

【题目大意】

一个N*N的网格,每个单元都有一个价值Vi的宝物和一个高度Hi。现在ZhouGuyue要作至多K次旅行,每次旅行如下:他可以借助bin3的直升机飞到任意一个单元,之后他每次只能向相邻的且高度比当前所在格子低的格子移动。当他移动到一个边界的格子上时,他可以跳出这个网格并完成一次旅行。旅行中所到之处的宝物他可以全部拿走,一旦拿走原来的格子里就没有宝物了。问他最多能拿走价值多少的宝物。(1 <= N <= 50, 0 <= K <= 50, 0 <= Vi <= 10000)  
【建模方法】 
将每个格子i拆成两个点i’, i’’并加边(i’, i’’, 1, -Vi), (i’, i’’, ∞, 0), (s, i’, ∞, 0);对相邻的四个格子j,若Hi > Hj则加边(i’’, j’, ∞, 0);若格子i在边界上则加边(i’’, t, ∞, 0)。限制增广次数小于等于K求最小费用流即可。

以上摘自Edelweiss《网络流建模汇总》

启示:

1.增广次数做了限制的问题还是比较好解决的,对每次增广后用计数器次数统计就可以了。

2.这里要求费用尽量大,可以把所有费用赋为-value,然后做费用流,得到结果的相反数就是最大的费用。

3.有的边,当第一次经过它时,可获利cost,以后经过便不再获利,则加两天边(u,v,1,-cost),(u,v,INF,0)。其实就是每种情况都对应一条边。同时,由最短路的性质,当前节点u一定会选择一条边权尽量小的边线走,因此可以保证第一次经过时的获利。

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <cmath>
  5 #include <queue>
  6 #define maxn 5010
  7 #define maxm 100000
  8 #define INF 1<<30
  9 using namespace std;
 10 
 11 int N,K;
 12 struct MCMF{
 13     int src,sink,e,n;
 14     int first[maxn];
 15     int cap[maxm],cost[maxm],v[maxm],next[maxm];
 16     bool flag;
 17     void init(){
 18         e = 0;
 19         memset(first,-1,sizeof(first));
 20     }
 21 
 22     void add_edge(int a,int b,int cc,int ww){
 23         //printf("add:%d to %d,cap = %d,cost = %d
",a,b,cc,ww);
 24         cap[e] = cc;cost[e] = ww;v[e] = b;
 25         next[e] = first[a];first[a] = e++;
 26         cap[e] = 0;cost[e] = -ww;v[e] = a;
 27         next[e] = first[b];first[b] = e++;
 28     }
 29 
 30     int d[maxn],pre[maxn],pos[maxn];
 31     bool vis[maxn];
 32 
 33     bool spfa(int s,int t){
 34         memset(pre,-1,sizeof(pre));
 35         memset(vis,0,sizeof(vis));
 36         queue<int> Q;
 37         for(int i = 0;i <= n;i++)   d[i] = INF;
 38         Q.push(s);pre[s] = s;d[s] = 0;vis[s] = 1;
 39         while(!Q.empty()){
 40             int u = Q.front();Q.pop();
 41             vis[u] = 0;
 42             for(int i = first[u];i != -1;i = next[i]){
 43                 if(cap[i] > 0 && d[u] + cost[i] < d[v[i]]){
 44                     d[v[i]] = d[u] + cost[i];
 45                     pre[v[i]] = u;pos[v[i]] = i;
 46                     if(!vis[v[i]])  vis[v[i]] = 1,Q.push(v[i]);
 47                 }
 48             }
 49         }
 50         return pre[t] != -1;
 51     }
 52 
 53     int Mincost;
 54     int Maxflow;
 55 
 56     int MinCostFlow(int s,int t,int nn){
 57         Mincost = 0,Maxflow = 0,n = nn;
 58         int cnt = 0;
 59         while(spfa(s,t)){
 60             cnt++;
 61             if(cnt > K) break;
 62             int min_f = INF;
 63             for(int i = t;i != s;i = pre[i])
 64                 if(cap[pos[i]] < min_f) min_f = cap[pos[i]];
 65             Mincost += d[t] * min_f;
 66             Maxflow += min_f;
 67             for(int i = t;i != s;i = pre[i]){
 68                 cap[pos[i]] -= min_f;
 69                 cap[pos[i]^1] += min_f;
 70             }
 71         }
 72         return Mincost;
 73     }
 74 };
 75 
 76 MCMF g;
 77 int value[55][55],h[55][55];
 78 
 79 inline int id(int i,int j){
 80     return i*N + j;
 81 }
 82 
 83 int dx[] = {0,1,0,-1};
 84 int dy[] = {1,0,-1,0};
 85 int main(){
 86     int kase;
 87     scanf("%d",&kase);
 88     while(kase--){
 89         g.init();
 90         scanf("%d%d",&N,&K);
 91         for(int i = 0;i < N;i++)
 92             for(int j = 0;j < N;j++)
 93                 scanf("%d",&value[i][j]);
 94         for(int i = 0;i < N;i++)
 95             for(int j = 0;j < N;j++)
 96                 scanf("%d",&h[i][j]);
 97         int S = N*N*2,T = S+1;
 98         for(int i = 0;i < N;i++){
 99             for(int j = 0;j < N;j++){
100                 g.add_edge(S,id(i,j),INF,0);
101                 g.add_edge(id(i,j),id(i,j)+N*N,1,-value[i][j]);
102                 g.add_edge(id(i,j),id(i,j)+N*N,INF,0);
103                 for(int k = 0;k < 4;k++){
104                     int x = i + dx[k];
105                     int y = j + dy[k];
106                     if(x < 0 || x >= N || y < 0 || y >= N)  continue;
107                     if(h[i][j] <= h[x][y])  continue;
108                     g.add_edge(id(i,j)+N*N,id(x,y),INF,0);
109                 }
110                 if(i == 0 || i == N-1 || j == 0 || j == N-1){
111                     g.add_edge(id(i,j)+N*N,T,INF,0);
112                 }
113             }
114         }
115         //printf("OK
");
116         int ans = g.MinCostFlow(S,T,T);
117         printf("%d
",-ans);
118     }
119 }
View Code
原文地址:https://www.cnblogs.com/zhexipinnong/p/3353821.html