HDU 3376 费用流 Matrix Again

题意:

给出一个n × n的矩阵,每个格子中有一个数字代表权值,找出从左上角出发到右下角的两条不相交的路径(起点和终点除外),使得两条路径权值之和最大。

分析:

如果n比较小的话是可以DP的,但是现在n非常大,DP会超时的。

这个用费用流来求解:

因为每个点只能走一次,所以先拆点,两点之间连一条容量为1费用为对应格子权值的边,如果是起点或终点,因为要走两次,所以要连容量为2的边。

对于不同格子之间,如果能到达,连一条容量为INF,费用为0的边。

因为算法求的是最小费用,所以我们把每个格子的相反数当做费用去连边,最后再取相反数。

因为起点和终点容量为2,计算出来的最大权值重复计算了左上角和右下角的权值,所以答案应该再减去这两个数。

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <algorithm>
  5 #include <vector>
  6 #include <queue>
  7 using namespace std;
  8 
  9 const int maxn = 600;
 10 const int maxnode = maxn * maxn * 2;
 11 const int maxm = 1000000 + 10;
 12 const int INF = 0x3f3f3f3f;
 13 
 14 struct Edge
 15 {
 16     int from, to, cap, flow, cost;
 17     int nxt;
 18     Edge() {}
 19     Edge(int u, int v, int cap, int f, int cost, int nxt):from(u), to(v), cap(cap), flow(f), cost(cost), nxt(nxt) {}
 20 };
 21 
 22 int ecnt;
 23 Edge edges[maxm << 2];
 24 int head[maxnode];
 25 
 26 void AddEdge(int u, int v, int cap, int cost)
 27 {
 28     edges[ecnt] = Edge(u, v, cap, 0, cost, head[u]);
 29     head[u] = ecnt++;
 30     edges[ecnt] = Edge(v, u, 0, 0, -cost, head[v]);
 31     head[v] = ecnt++;
 32 }
 33 
 34 int row;
 35 int A[maxn][maxn];
 36 
 37 int n;
 38 int d[maxnode + 10], p[maxnode + 10], a[maxnode + 10];
 39 bool inq[maxnode + 10];
 40 
 41 bool SPFA(int s, int t)
 42 {
 43     memset(inq, false, sizeof(inq));
 44     memset(p, -1, sizeof(p));
 45     memset(d, 0x3f, sizeof(d));
 46     inq[s] = true;
 47     d[s] = 0;
 48     a[s] = INF;
 49 
 50     queue<int> Q;
 51     Q.push(s);
 52     while(!Q.empty())
 53     {
 54         int u = Q.front(); Q.pop(); inq[u] = false;
 55         for(int i = head[u]; ~i; i = edges[i].nxt)
 56         {
 57             Edge& e = edges[i];
 58             int v = e.to;
 59             if(e.flow < e.cap && d[u] + e.cost < d[v])
 60             {
 61                 d[v] = d[u] + e.cost;
 62                 p[v] = i;
 63                 a[v] = min(a[u], e.cap - e.flow);
 64                 if(!inq[v]) { inq[v] = true; Q.push(v); }
 65             }
 66         }
 67     }
 68 
 69     return d[t] != INF;
 70 }
 71 
 72 int Mincost(int s, int t)
 73 {
 74     int flow = 0;
 75     int cost = 0;
 76     while(SPFA(s, t))
 77     {
 78         flow += a[t];
 79         cost += d[t] * a[t];
 80         int u = t;
 81         while(u != s)
 82         {
 83             edges[p[u]].flow += a[t];
 84             edges[p[u]^1].flow -= a[t];
 85             u = edges[p[u]].from;
 86         }
 87     }
 88     return cost;
 89 }
 90 
 91 int main()
 92 {
 93     while(scanf("%d", &row) == 1)
 94     {
 95         for(int i = 0; i < row; i++)
 96             for(int j = 0; j < row; j++) scanf("%d", &A[i][j]);
 97 
 98         n = row * row;
 99         int s = 0, t = n * 2 - 1;
100         ecnt = 0;
101         memset(head, -1, sizeof(head));
102 
103         //build graph
104         for(int i = 0; i < row; i++)
105             for(int j = 0; j < row; j++)
106             {
107                 int u = i * row + j;
108                 int v = u + n;
109                 int cap = 1;
110                 if(u == 0 || u == n - 1) cap++;
111                 AddEdge(u, v, cap, -A[i][j]);
112 
113                 int w;
114                 if(i < row - 1)
115                 {
116                     w = u + row;
117                     AddEdge(v, w, INF, 0);
118                 }
119                 if(j < row - 1)
120                 {
121                     w = u + 1;
122                     AddEdge(v, w, INF, 0);
123                 }
124             }
125 
126         n <<= 1;
127         printf("%d
", -Mincost(s, t) - A[0][0] - A[row-1][row-1]);
128     }
129 
130     return 0;
131 }
代码君
原文地址:https://www.cnblogs.com/AOQNRMGYXLMV/p/4790006.html