• hoj 2715 (费用流 拆点)


    http://acm.hit.edu.cn/hoj/problem/view?id=2715

    将每个格子 i 拆成两个点 i’, i’’并加边(i’, i’’, 1, -Vi), (i’, i’’, ∞, 0), (s, i’, ∞, 0); 控制只有一次能取到宝物。

    对相邻的四个格子 j, Hi > Hj 则加边(i’’, j’, ∞, 0);

    若格子 i 在边界上则加边(i’’, t, ∞, 0)。

    限制增广次数小于等于 K 求最小费用流即可。

      1 #include <iostream>
      2 #include <cstdio>
      3 #include <cstring>
      4 #include <algorithm>
      5 #include <queue>
      6 #include <cmath>
      7 
      8 using namespace std;
      9 
     10 const int maxn = 505;
     11 const int maxm = 2000;
     12 const int inf = 0x3f3f3f3f;
     13 
     14 struct MCMF
     15 {
     16     struct Edge
     17     {
     18         int v, c, w, next;
     19     }p[maxm << 1];
     20     int e, head[maxn], dis[maxn], pre[maxn], cnt[maxn], sumFlow, n;
     21     bool vis[maxn];
     22     void init(int nt)
     23     {
     24         e = 0; n = nt;
     25         memset(head, -1, sizeof(head[0]) * (n + 2) );
     26     }
     27     void addEdge(int u, int v, int c, int w)
     28     {
     29         p[e].v = v; p[e].c = c; p[e].w = w; p[e].next = head[u]; head[u] = e++;
     30         swap(u, v);
     31         p[e].v = v; p[e].c = 0; p[e].w = -w; p[e].next = head[u]; head[u] = e++;
     32     }
     33     bool spfa(int S, int T)
     34     {
     35         queue <int> q;
     36         for (int i = 0; i <= n; ++i)
     37             vis[i] = cnt[i] = 0, pre[i] = -1, dis[i] = inf;
     38         vis[S] = 1, dis[S] = 0;
     39         q.push(S);
     40         while (!q.empty())
     41         {
     42             int u = q.front(); q.pop();
     43             vis[u] = 0;
     44             for (int i = head[u]; i + 1; i = p[i].next)
     45             {
     46                 int v = p[i].v;
     47                 if (p[i].c && dis[v] > dis[u] + p[i].w)
     48                 {
     49                     dis[v] = dis[u] + p[i].w;
     50                     pre[v] = i;
     51                     if (!vis[v])
     52                     {
     53                         q.push(v);
     54                         vis[v] = 1;
     55                         if (++cnt[v] > n) return 0;
     56                     }
     57                 }
     58             }
     59         }
     60         return dis[T] != inf;
     61     }
     62     int mcmf(int S, int T, int kt)
     63     {
     64         sumFlow = 0;
     65         int minFlow = 0, minCost = 0;
     66         while (spfa(S, T) && (kt--))
     67         {
     68             minFlow = inf + 1;
     69             for (int i = pre[T]; i + 1; i = pre[ p[i ^ 1].v ])
     70                 minFlow = min(minFlow, p[i].c);
     71             sumFlow += minFlow;
     72             for (int i = pre[T]; i + 1; i = pre[ p[i ^ 1].v ])
     73             {
     74                 p[i].c -= minFlow;
     75                 p[i ^ 1].c += minFlow;
     76             }
     77             minCost += dis[T] * minFlow;
     78         }
     79         return minCost;
     80     }
     81     void build(int nt, int kt)
     82     {
     83         int nnt = nt * nt;
     84         init(nnt * 2 + 1);
     85         int val[53][53], height[53][53];
     86         memset(val, 0x3f, sizeof(val));
     87         memset(height, 0x3f, sizeof(height));
     88         for (int i = 1; i <= nt; ++i)
     89             for (int j = 1; j <= nt; ++j)
     90                 scanf("%d", &val[i][j]);
     91         for (int i = 1; i <= nt; ++i)
     92             for (int j = 1; j <= nt; ++j)
     93                 scanf("%d", &height[i][j]);
     94         for (int i = 1; i <= nt; ++i)
     95             for (int j = 1; j <= nt; ++j)
     96             {
     97                 int pos = nt * (i - 1) + j;
     98                 addEdge(0, pos, inf, 0);
     99                 addEdge(pos, pos + nnt, 1,-val[i][j]);
    100                 addEdge(pos, pos + nnt, inf,0);
    101                 if (i == 1 || i == nt || j == 1 || j == nt)
    102                     addEdge(pos + nnt, n, inf, 0);
    103                 if (height[i][j] > height[i][j - 1])
    104                     addEdge(pos + nnt, pos - 1, inf, 0);
    105                 if (height[i][j] > height[i][j + 1])
    106                     addEdge(pos + nnt, pos + 1, inf, 0);
    107                 if (height[i][j] > height[i - 1][j])
    108                     addEdge(pos + nnt, pos - nt, inf, 0);
    109                 if (height[i][j] > height[i + 1][j])
    110                     addEdge(pos + nnt, pos + nt, inf, 0);
    111             }
    112     }
    113     void solve(int nt, int kt)
    114     {
    115         build(nt, kt);
    116         printf("%d
    ", - mcmf(0, n, kt));
    117     }
    118 }my;
    119 int main()
    120 {
    121     int tcase, n, k;
    122     scanf("%d", &tcase);
    123     while (tcase--)
    124     {
    125         scanf("%d%d", &n, &k);
    126         my.solve(n, k);
    127     }
    128     return 0;
    129 }
  • 相关阅读:
    一条语句批量插入多条数据
    VMware Workstation 15 Pro 永久激活密钥
    windows下java项目打包、启动批处理 .bat文件
    java简写名词解释
    windows查看所有进程:netstat -ano
    Java验证jwt token
    【转载】三种方法从 HTTPS 网站导出 SSL 证书链
    使用solr将CSV/XML/DB/JSON数据发布为Rest Service
    检验多个xsd的xml是否合法
    Eclipse 打包运行maven项目
  • 原文地址:https://www.cnblogs.com/Missa/p/3266188.html
Copyright © 2020-2023  润新知