坐井观天

In the name of dream

导航

POJ 2391 floyd + 拆点构图 + 二分 + 最大流

Posted on 2012-06-16 11:16  一毛_  阅读(304)  评论(1编辑  收藏  举报

题目链接: http://poj.org/problem?id=2391

题目大意:

  F个field,每个field有cow头牛和col个容量,给定field之间的距离,问如果分配合理的话,即每个field容纳允许数量的牛,且每头牛都进入相应的field,那么路程最远的牛的要走的最短路程是多少? (可能需要通过一些field到达指定的field)

 

分析:

  首先由floyd求出各个field的最短路map[i][j],

  然后二分枚举答案mid进行构图,超级源点ST向1……F分别连边,容量为相应的col,F+1……F+C分别向超级汇点ED连边,容量为相应的cow,然后对于i (1……F)向 j (F+1……F+C)两两判断是否连边,连边要求是:dis[ i ][ j-F ]<=mid,否则不连,容量为无穷大,然后用sap求出最大流flow与 sum{ cow }比较。

 

注意点:

1、二分答案上限limit的确定,limit= sum( weight )// 即输入的数据认为是一条链那么所有边权之和是一个上限。

2、距离的初始化为无穷大dis_inf,  dis_inf应该很大很大方便写代码,开始我没弄好数据用了-1表示很麻烦。

 

代码:

poj2391
  1 /*2391    Accepted    952K    204MS    C++    3646B    2012-06-16 08:11:04*/
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <cmath>
  5 #include <iostream>
  6 #include <algorithm>
  7 #include <vector>
  8 using namespace std;
  9 
 10 #define mpair make_pair
 11 #define pii pair<int,int>
 12 #define MM(a,b) memset(a,b,sizeof(a));
 13 typedef long long lld;
 14 typedef unsigned long long u64;
 15 template<class T> bool up_max(T& a,const T& b){return b>a? a=b,1 : 0;}
 16 template<class T> bool up_min(T& a,const T& b){return b<a? a=b,1 : 0;}
 17 #define maxn 410
 18 #define maxm 82000
 19 const int col_inf= 200000000;
 20 const lld dis_inf= 10000000000000000LL;
 21 
 22 int n,m;
 23 int ST, ED, NV;
 24 int cow[maxn], col[maxn];
 25 lld map[maxn][maxn];
 26 lld limit;
 27 
 28 void Floyd(){
 29     for(int k=1;k<=n;++k)
 30         for(int i=1;i<=n;++i)
 31             if( i!=k && map[i][k]!=dis_inf )
 32                 for(int j=1;j<=n;++j)
 33                     if( j!=i && j!=k && map[k][j]!=dis_inf )
 34                         up_min( map[i][j], map[i][k] + map[k][j] );
 35 }
 36 
 37 int top, head[maxn];
 38 struct Edge{
 39     int v,w,next;
 40     Edge(){}
 41     Edge(int v,int w,int next): v(v), w(w), next(next){}
 42 } edge[maxm];
 43 void Addedge(int u,int v,int w){
 44     edge[top]= Edge( v, w, head[u] );
 45     head[u]= top++;
 46     edge[top]= Edge( u, 0, head[v] );
 47     head[v]= top++;
 48 }
 49 
 50 void build_graph(lld len){
 51     ST= 0; ED= n+n+1, NV= n+n+2;
 52     top= 0;
 53     fill( head, head+NV, -1 ); ///
 54     for(int i=1;i<=n;++i){
 55         if( col[i]>0 ){ ///
 56             Addedge( ST, i, col[i] );
 57             for(int j=1;j<=n;++j)
 58                 if( cow[j]>0 && map[i][j]<=len )
 59                     Addedge( i, n+j, col_inf );
 60         }
 61         if( cow[i]>0 )
 62             Addedge( n+i, ED, cow[i] );
 63     }
 64 }
 65 
 66 int lay[maxn], pre[maxn], gap[maxn], cur[maxn];
 67 int sap(lld mid){
 68     build_graph(mid);
 69 
 70     int ret= 0;
 71     for(int i=0;i<NV;++i) lay[i]= gap[i]= 0, cur[i]= head[i];
 72     int u= pre[ST]= ST; ///
 73     int v, aug= col_inf;
 74     gap[0]= NV;
 75     while( lay[ST]<NV ){
 76         for(int &i= cur[u];i!=-1;i=edge[i].next){
 77             v= edge[i].v;
 78             if( edge[i].w && lay[u]==lay[v]+1 ) break;
 79         }
 80         if( -1!=cur[u] ){
 81             up_min( aug, edge[cur[u]].w );
 82             pre[v]= u;
 83             u= v;
 84             if( v==ED ){
 85                 ret+= aug;
 86                 for(u=pre[u];v!=ST;v=u,u=pre[u]){
 87                     edge[ cur[u] ].w -= aug;
 88                     edge[ cur[u]^1 ].w += aug;
 89                 }
 90                 aug= col_inf;
 91             }
 92         }
 93         else{
 94             int mindis= NV;
 95             for(int i=head[u];i!=-1;i=edge[i].next){
 96                 int v= edge[i].v;
 97                 if( edge[i].w && up_min( mindis, lay[v] ) )
 98                     cur[u]= i;
 99             }
100             if( --gap[ lay[u] ] == 0 ) break;
101             ++gap[ lay[u]=mindis+1 ];
102             u= pre[u];
103         }
104     }
105     return ret;
106 }
107 
108 lld solve(int tot){
109     lld l=1, r= limit, mid, ret= -1;
110     while( l<=r ){
111         mid= (l+r)>>1;
112         if( sap(mid) == tot ) r= mid-1, ret= mid;
113         else l= mid+1;
114     }
115     return ret;
116 }
117 
118 int main()
119 {
120     //freopen("poj2391.in","r",stdin);
121     while( cin>>n>>m ){
122         int tot= 0;
123         for(int i=1;i<=n;++i) scanf("%d%d", cow+i, col+i), tot+= cow[i];
124         for(int i=1;i<=n;++i) for(int j=1;j<=n;++j) map[i][j]= i==j ? 0 : dis_inf;
125 
126         limit= 0;
127         for(int i=1;i<=m;++i){
128             int x,y,t;
129             scanf("%d%d%d", &x, &y, &t);
130             limit+= t;
131             if( up_min( map[x][y], (lld)t ) )
132                 map[y][x]= t;
133         }
134         Floyd();
135 
136         lld ans= solve( tot );
137         cout<< ans <<endl;
138     }
139 }