题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1001
最小割转化最短路的经典题目。
题目看起来是求最小割,看一下割和最小割的定义:
割: 对一个图,把所有顶点分成两个集合 S 和 T=V-S ,其中源点 s 在集合 S 中,汇点 t 在集合 T 中。如果把 “起点在 S 中,终点在 T 中” 的边全部删除,就无法从 s 到达 t 了。这样的集合划分 (S,T)称为一个 s-t 割,它的容量为起点在 S 中,终点在 T 中的所有边的容量和。
最小割: 图中容量最小的割。
由最小割最大流定理:
For any network having a single origin and single destination node, the maximum possible flow from origin to destination equals the minimum cut value for all cuts in the network.
那么跑一遍最大流就出来了?但是V,E都能达到1e3,我所知的最快网络流算法ISAP都要O(V^2 E),所以网络流不可行。
题目中这样的图被称为s-t平面图,这样的图作它的对偶图求最短路。
具体看周冬的《两极相通——浅析最大最小定理在信息学竞赛中的应用》
1 /* 2 * Problem: bzoj 1001 3 * Author: SHJWUDP 4 * Created Time: 2015/3/26 星期四 16:36:42 5 * File Name: 233.cpp 6 * State: Accepted 7 * Memo: 网络流->最短路 8 */ 9 #include <iostream> 10 #include <cstdio> 11 #include <cstring> 12 #include <algorithm> 13 #include <queue> 14 15 using namespace std; 16 17 const int INF=0x7f7f7f7f; 18 19 const int MaxA=1e3+7; 20 const int MaxB=MaxA*MaxA*2; 21 const int MaxC=MaxA*MaxA*3; 22 23 struct Edge { 24 int v, nt; 25 int w; 26 } edges[MaxC]; 27 28 int head[MaxB], edgeNum; 29 30 int N, M; 31 int s, t; 32 33 void init(int n) { 34 memset(head, -1, sizeof(head[0])*(n+3)); 35 edgeNum=0; 36 } 37 void addEdge(int u, int v, int w) { 38 edges[edgeNum].v=v; 39 edges[edgeNum].w=w; 40 edges[edgeNum].nt=head[u]; 41 head[u]=edgeNum++; 42 } 43 namespace Dijkstra { 44 struct HeapNode { 45 int d, u; 46 HeapNode(int d, int u):d(d), u(u) {} 47 bool operator<(const HeapNode& rhs) const { 48 return d > rhs.d; 49 } 50 }; 51 52 int n; 53 int d[MaxA*MaxA<<1]; 54 bool done[MaxA*MaxA<<1]; 55 int go(int s) { 56 memset(d, 0x7f, sizeof(d[0])*(n+3)); 57 memset(done, 0, sizeof(done[0])*(n+3)); 58 d[s]=0; done[s]=1; 59 priority_queue<HeapNode> Q; 60 Q.push(HeapNode(0, s)); 61 while(!Q.empty()) { 62 HeapNode x=Q.top(); Q.pop(); 63 for(int i=head[x.u]; ~i; i=edges[i].nt) { 64 Edge& e=edges[i]; 65 if(d[e.v]>d[x.u]+e.w) { 66 d[e.v]=d[x.u]+e.w; 67 if(!done[e.v]) { 68 done[e.v]=1; 69 Q.push(HeapNode(d[e.v], e.v)); 70 } 71 } 72 } 73 } 74 return d[t]>=INF?0:d[t]; 75 } 76 } 77 int main() { 78 #ifndef ONLINE_JUDGE 79 freopen("in", "r", stdin); 80 //freopen("out", "w", stdout); 81 #endif 82 while(~scanf("%d%d", &N, &M)) { 83 s=(N-1)*(M-1)*2+1; t=(N-1)*(M-1)*2+2; 84 init(Dijkstra::n=(N-1)*(M-1)*2+2); 85 int x; 86 for(int i=0; i<N; i++) 87 for(int j=0; j<M-1; j++) { 88 scanf("%d", &x); 89 addEdge(i==0?s:((i-1)*(M-1)+j)<<1|1, i==N-1?t:(i*(M-1)+j)<<1, x); 90 } 91 for(int i=0; i<N-1; i++) 92 for(int j=0; j<M; j++) { 93 scanf("%d", &x); 94 addEdge(j==M-1?s:(i*(M-1)+j)<<1|1, j==0?t:(i*(M-1)+(j-1))<<1, x); 95 } 96 for(int i=0; i<N-1; i++) 97 for(int j=0; j<M-1; j++) { 98 scanf("%d", &x); 99 addEdge((i*(M-1)+j)<<1, (i*(M-1)+j)<<1|1, x); 100 } 101 102 printf("%d ", Dijkstra::go(s)); 103 } 104 return 0; 105 }