题意:F个地区。已知各个地区之间的行走时间。每个地区I有两个属性:
这个地区当前牛的个数,下雨的时候这个地区实际能够容纳牛的个数。
问至少需要多少时间,使所有的牛在下雨的时候都能够被容纳。
构图:先Floyd求所有点对之间最短路。二分最短时间,源向I连容量为初始牛数的边,I’向汇连容量为所能容纳牛数的边,I向I’连容量无穷大的边,若I,J能够在mid时间内到达,则连无穷大的边,用最大流判可行性。
注意几点:
1.点之间的距离非常大,鄙人宏定义1500000005000,同时注意long long的使用;
2.无向图;
3.自己可以流向自己;
4.拆点:1流向2,2流向3并不意味着1能流向3。
View Code
/*Source Code Problem: 2391 User: HEU_daoguang Memory: 3132K Time: 375MS Language: G++ Result: Accepted Source Code*/ #include <iostream> #include <stdio.h> #include <string.h> using namespace std; int n,m; #define infx 1500000005000 #define inf 20000000 #define V 3000 #define E 200000 struct Node{ int s,t; }point[V]; long long map[V][V]; int cnt; int dist[V]; int head[V]; int que[V]; int sta[V]; struct Edge { int u,v,c,next; }edge[4*E]; void init(){ cnt=0; memset(head,-1,sizeof(head)); } void addedge(int u,int v,int c){ edge[cnt].u=u;edge[cnt].v=v;edge[cnt].c=c; edge[cnt].next=head[u];head[u]=cnt++; edge[cnt].u=v;edge[cnt].v=u;edge[cnt].c=0; edge[cnt].next=head[v];head[v]=cnt++; } int dinic(int s,int t){ int ans=0; while(true){ int left,right,u,v; memset(dist,-1,sizeof(dist)); left=right=0; que[right++]=s; dist[s]=0; while(left<right){ u=que[left++]; for(int k=head[u];k!=-1;k=edge[k].next){ u=edge[k].u; v=edge[k].v; if(edge[k].c > 0 && dist[v]==-1){ dist[v]=dist[u]+1; que[right++]=v; if(v==t){ left=right; break; } } } } if(dist[t]==-1) break; int top=0; int now=s; while(true){ if(now!=t){ int k; for(k=head[now];k!=-1;k=edge[k].next){ if(edge[k].c>0 && dist[edge[k].v]==dist[edge[k].u]+1) break; } if(k!=-1){ sta[top++]=k; now=edge[k].v; } else{ if(top==0) break; dist[edge[sta[--top]].v]=-1; now=edge[sta[top]].u; } } else{ int flow=inf,ebreak; for(int i=0;i<top;i++){ if(flow>edge[sta[i]].c){ flow=edge[sta[i]].c; ebreak=i; } } ans+=flow; for(int i=0;i<top;i++){ edge[sta[i]].c-=flow; edge[sta[i]^1].c+=flow; } now=edge[sta[ebreak]].u; top=ebreak; } } } return ans; } int main() { //freopen("in.txt","r",stdin); int a,b,c,sum; while(scanf("%d%d",&n,&m)!=EOF){ for(int i=1;i<=n;i++) for(int j=1;j<=n;j++){ if(i==j) map[i][j]=0; else map[i][j]=infx; } sum=0; for(int i=1;i<=n;i++){ scanf("%d%d",&point[i].s,&point[i].t); sum+=point[i].s; } while(m--){ scanf("%d%d%d",&a,&b,&c); if(c<map[a][b]) map[a][b]=map[b][a]=c; } for(int k=1;k<=n;k++) for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) map[i][j]=min(map[i][j],map[i][k]+map[k][j]); long long l=-1,r=infx,mid; int flag=0; while(l<r){ mid=(l+r)/2; init(); for(int i=1;i<=n;i++){ addedge(0,i,point[i].s); addedge(i+n,2*n+1,point[i].t); } for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) if(map[i][j]<=mid) addedge(i,j+n,inf); if(dinic(0,2*n+1)==sum) r=mid,flag=1; else l=mid+1; } if(flag) printf("%lld\n",r); else printf("-1\n"); } return 0; }