shjwudp

导航

 

题目链接: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\n", Dijkstra::go(s));
103     }
104     return 0;
105 }
bzoj 1001

 

posted on 2015-04-02 14:22  shjwudp  阅读(123)  评论(0编辑  收藏  举报