poj2391:http://poj.org/problem?id=2391
题意:一个人有n个农场,每个农场都一个避雨的地方,每个农场有一些牛,每个避雨的地方能容纳牛的数量是有限的。农场之间有一些道路可以连通。现在给出每个农场的牛的数量以及每个避雨点的值,问你所有的牛都找到一个避雨点的时间最短是多少。
题解:本题个人认为对于初学者来说,比较难了。看了别人的题解,本题的考察的知识点有:Floyd+二分+网络最大流,以及图论里面的拆点和建图。首先:对于所有的牛来说,如果农场是连通的,则最短的时间最坏的情况是任意两点之间距离的最大值所以要用Floyd来求n源最短路。然后最初最大的那个值。第二:建图,超级源点0,会点2*n+1,然后拆点,把那个农场拆成2*n个点,
例如:4个点的话
1 5
2 6
3 7
4 8
然后建边,以上的点,左边的点与0点建边,边权的容量为每个农改现在的牛的数量,右边的点与会点建边,边的容量为每个避雨点的容量。然后1和5之间,2和6之间建边,边权INF,然后二分答案(就是刚才的那个最大数值),对于任意的两点之间,如果两点之间的距离小于这个最大值,说明可以由i这个点牛向j移动所以i和j+n之间要建边,边权INF
每一二分答案,跑最大流,如果最大流等于牛的总数,说明这个距离满足条件,继续缩小距离再跑,知道不行就停止,则此时的距离就是最短的距离,保证所有牛都能找到避雨点的距离。
注意:本题的数据,距离会爆出int
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<queue> 6 using namespace std; 7 const int INF=100000000; 8 const int MAXN=505; 9 const long long INFs=100000000000000LL; 10 int val1[MAXN],val2[MAXN]; 11 struct Node{ 12 int f; 13 int c; 14 }; 15 long long dist[MAXN][MAXN];//求最短路 16 int pre[MAXN];//网络流的分层 17 Node map[MAXN][MAXN];//网络流的图 18 int n,m; 19 int se,sx;//会点和源点 20 bool BFS(){//层次网络 21 memset(pre,0,sizeof(pre)); 22 queue<int>Q; 23 Q.push(0); 24 pre[0]=1; 25 while(!Q.empty()){ 26 int v=Q.front(); 27 Q.pop(); 28 for(int i=0;i<=2*n+1;i++) 29 if(!pre[i]&&map[v][i].c-map[v][i].f){ 30 pre[i]=pre[v]+1; 31 Q.push(i); 32 } 33 } 34 return pre[se]!=0; 35 } 36 int dinic(int pos,int flow){//网路流 37 int f=flow; 38 if(pos==se) 39 return flow; 40 for(int i=0;i<=2*n+1;i++){ 41 if(map[pos][i].c-map[pos][i].f&&pre[i]==pre[pos]+1){ 42 int a=map[pos][i].c-map[pos][i].f; 43 int temp=dinic(i,min(a,flow)); 44 map[pos][i].f+=temp; 45 map[i][pos].f-=temp; 46 flow-=temp; 47 } 48 } 49 return f-flow; 50 } 51 int slove(){//总流 52 int sum=0; 53 while(BFS()) 54 sum+=dinic(sx,INF); 55 return sum; 56 } 57 void build(long long limit){//建图 58 memset(map,0,sizeof(map)); 59 for(int i=1;i<=n;i++) 60 if(val1[i]){ 61 map[0][i].c=val1[i]; 62 map[0][i].f=0; 63 map[i][i+n].c=INF; 64 map[i][i+n].f=0; 65 } 66 for(int i=1;i<=n;i++){ 67 if(val2[i]){ 68 map[i+n][2*n+1].c=val2[i]; 69 map[i+n][2*n+1].f=0; 70 } 71 } 72 for(int i=1;i<=n;i++) 73 for(int j=1;j<=n;j++){ 74 if(dist[i][j]<=limit&&i!=j){ 75 map[i][j+n].c=INF; 76 map[i][j+n].f=0; 77 } 78 } 79 } 80 long long Floyd(){//求n源最短路 81 for(int k=1;k<=n;k++) 82 for(int i=1;i<=n;i++) 83 for(int j=1;j<=n;j++){ 84 if(i!=k&&i!=j&&k!=j&&dist[i][k]+dist[k][j]<dist[i][j]) 85 dist[i][j]=dist[i][k]+dist[k][j]; 86 } 87 long long ans=0;//注意这里初始化,因为一下的可能不会执行,可能没有满足条件ans 88 for(int i=1;i<=n;i++) 89 for(int j=1;j<=n;j++) 90 if(dist[i][j]<INFs&&dist[i][j]>ans) 91 ans=dist[i][j]; 92 return ans; 93 } 94 void init(){//初始化 95 memset(val1,0,sizeof(val1)); 96 memset(val2,0,sizeof(val2)); 97 for(int i=1;i<=n;i++) 98 for(int j=1;j<=n;j++) 99 dist[i][j]=INFs; 100 } 101 int main(){ 102 int c,f,u,v,sum;long long w; 103 while(~scanf("%d%d",&n,&m)){ 104 init();sum=0;sx=0;se=2*n+1; 105 for(int i=1;i<=n;i++){ 106 scanf("%d%d",&f,&c); 107 val1[i]=f;val2[i]=c; 108 sum+=f; 109 } 110 for(int i=1;i<=m;i++){ 111 scanf("%d %d %I64d",&u,&v,&w); 112 if(w<dist[u][v]) 113 dist[u][v]=dist[v][u]=w; 114 } 115 long long r=Floyd(),ans=-1,l=0; 116 while(l<=r){//二分答案,不断缩小答案 117 long long mid=(l+r)/2; 118 build(mid); 119 if(slove()>=sum){ 120 r=mid-1;ans=mid; 121 } 122 else 123 l=mid+1; 124 } 125 printf("%I64d ",ans); 126 } 127 }