zoukankan      html  css  js  c++  java
  • [洛谷P2045]方格取数加强版

    题目传送门

    还记得原版方格取数怎么做的吧?$DP$。

    当时的复杂度为$O(n^4)$。

    但现在$k leq 10$,所以原办法行不通。

    这道题发现一个数只能被取一次。

    然后就是找$k$条从$(1,1)$到$(n,n)$的路径使得覆盖的数值和最大。

    这个可以用网络流的相关知识求解(准确说是最小费用最大流)。

    将每个坐标的点拆成两个点$(x,y,a)$和$(x,y,b)$,表示该点的入点和出点。

    因为原图中可以向下走或向右走,所以连边$(x,y,b) ightarrow (x+1,y,a) && (x,y+1,a)$ ,流量为$INF$。费用为$0$(因为可以走无限次,且不产生贡献)

    连边$(x,y,a)$到$(x,y,b)$,流量为$1$,费用为对应方格的数$-A_{xy}$,满足了只取一次的要求,还要满足能再次经过且不产生贡献,所以再连一条边,流量为$INF$,费用为$0$。

    然后建超级源和超级汇$(s)$和$(t)$,连边$(s) ightarrow (1,1,a)$,流量为$k$,费用为$0$;连边$(n,n,b) ightarrow (t)$,流量为$k$,费用为$0$。

    跑一遍最小费用最大流即可。

    这里用了一个技巧:将实际的贡献设成负数。这样就会尽可能流过这个结点获得负的贡献达到目的。

    所以要用$SPFA$的网络流算法($SPFA$:我还没扑街233)。

    最后注意输出费用的相反数即可。

      1 #include <bits/stdc++.h>
      2 
      3 using namespace std;
      4 
      5 #define re register
      6 #define rep(i, a, b) for (re int i = a; i <= b; ++i)
      7 #define repd(i, a, b) for (re int i = a; i >= b; --i)
      8 #define maxx(a, b) a = max(a, b);
      9 #define minn(a, b) a = min(a, b);
     10 #define LL long long
     11 #define INF (1 << 30)
     12 
     13 inline int read() {
     14     int w = 0, f = 1; char c = getchar();
     15     while (!isdigit(c)) f = c == '-' ? -1 : f, c = getchar();
     16     while (isdigit(c)) w = (w << 3) + (w << 1) + (c ^ '0'), c = getchar();
     17     return w * f;
     18 }
     19 
     20 const int maxn = 50 * 50 + 5;
     21 
     22 struct Edge {
     23     int u, v, c, f, w, pre;
     24 };
     25 
     26 struct Graph {
     27     Edge ed[maxn << 3];
     28     int n, m, G[maxn << 1];
     29     void init(int n) {
     30         this->n = n;
     31         m = 1;
     32         memset(G, 0, sizeof(G));
     33     }
     34     void add(int u, int v, int c, int w) {
     35         ed[++m] = (Edge){u, v, c, 0, w, G[u]};
     36         G[u] = m;
     37         ed[++m] = (Edge){v, u, 0, 0, -w, G[v]};
     38         G[v] = m;
     39     }
     40     int a[maxn << 1], d[maxn << 1], inq[maxn << 1], p[maxn << 1];
     41     int s, t;
     42     queue<int> Q;
     43     bool bellmanford(int &flow, int &cost) {
     44         memset(inq, 0, sizeof(inq));
     45         rep(i, 1, n) d[i] = INF;
     46         inq[s] = 1; Q.push(s); p[s] = 0; a[s] = INF; d[s] = 0;
     47         while (!Q.empty()) {
     48             int u = Q.front(); Q.pop(); inq[u] = 0;
     49             for (register int i = G[u]; i; i = ed[i].pre) {
     50                 Edge &e = ed[i];
     51                 if (e.f < e.c && d[u] + e.w < d[e.v]) {
     52                     d[e.v] = d[u] + e.w;
     53                     a[e.v] = min(a[u], e.c-e.f);
     54                     p[e.v] = i;
     55                     if (!inq[e.v]) {
     56                         Q.push(e.v);
     57                         inq[e.v] = 1;
     58                     }
     59                 }
     60             }
     61         }
     62         if (d[t] == INF) return false;
     63         flow += a[t];
     64         cost += a[t] * d[t];
     65         for (register int i = t; p[i]; i = ed[p[i]].u) {
     66             ed[p[i]].f += a[t];
     67             ed[p[i]^1].f -= a[t];
     68         }
     69         return true;
     70     }
     71     int mincostmaxflow(int s, int t, int &cost) {
     72         this->s = s, this->t = t;
     73         int flow = 0; cost = 0;
     74         while (bellmanford(flow, cost));
     75         return flow;
     76     }
     77 } G;
     78 
     79 int n, k;
     80 
     81 #define id(x, y) ((x)*n+(y)-n)
     82 
     83 int main() {
     84     n = read(), k = read();
     85     G.init(n*n*2+2);
     86     rep(i, 1, n)
     87         rep(j, 1, n) {
     88             //a[i][j] = read();
     89             G.add(id(i, j), id(i, j)+n*n, 1, -read());
     90             G.add(id(i, j), id(i, j)+n*n, k, 0);
     91             if (i != n) G.add(id(i, j)+n*n, id(i+1, j), k, 0);
     92             if (j != n) G.add(id(i, j)+n*n, id(i, j+1), k, 0);
     93         }
     94     G.add(n*n*2+1, 1, k, 0);
     95     G.add(n*n*2, n*n*2+2, k, 0);
     96     int cost;
     97     G.mincostmaxflow(n*n*2+1, n*n*2+2, cost);
     98     printf("%d", -cost);
     99     return 0;
    100 }
  • 相关阅读:
    Java基本数据类型的包装类
    Java数据类型基础
    Xscan安装
    Notepad++配置HexEditor插件
    [WP]XCTF-re2-cpp-is-awesome
    [WP]XCTF-tt3441810
    [WP]XCTF-re1-100
    [WP]XCTF-Mysterious
    [WP]xctf-parallel-comparator-200
    [WP]XCTF-elrond32
  • 原文地址:https://www.cnblogs.com/ac-evil/p/10367411.html
Copyright © 2011-2022 走看看