题目链接: 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 }