zoukankan      html  css  js  c++  java
  • 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
  • 相关阅读:
    C++ Call C# COM
    C ++ / CLI 语法
    C#调用C++ DLL动态库的两种方式
    Linux下的JMeter部署及使用
    同时处理多请求(带超时时间)
    同时处理多请求
    curl命令
    mysql命令
    SpringBoot配置文件敏感信息加密-jasypt
    spring boot升级到2.x的坑
  • 原文地址:https://www.cnblogs.com/zhexipinnong/p/3353821.html
Copyright © 2011-2022 走看看