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\n", -Mincost(s, t) - A[0][0] - A[row-1][row-1]); 128 } 129 130 return 0; 131 }