题目背景
这本是一个非常简单的问题,然而奶牛们由于下雨已经非常混乱,无法完成这一计算,于是这个任务就交给了你。(奶牛混乱的原因看题目描述)
题目描述
在一个农场里有n块田地。某天下午,有一群牛在田地里吃草,他们分散在农场的诸多田地上,农场由m条无向的路连接,每条路有不同的长度。
突然,天降大雨,奶牛们非常混乱,想要快点去躲雨。已知每个田地都建立有一个牛棚,但是每个牛棚只能容纳一定数量的牛躲雨,如果超过这个数量,那多出的牛只能去别的田地躲雨。奶牛们每移动 1 的距离花费 1 时间,奶牛们想知道它们全部都躲进牛棚,最少需要多少时间。(即最后一头奶牛最少要花多久才能躲进牛棚)。
输入格式
第一行有两个整数,分别代表田地数 n 和道路数 m。
接下来 n 行,每行两个整数,第 (i+1) 行的整数 si,pisi,pi 分别表示第 ii 块田地的牛的数量以及该田地的牛棚最多可以容纳多少牛。
接下来 m 行,每行三个整数 u,v,w代表存在一条长度为 w 的连接 u 和 v 的道路。
输出格式
输出一行一个整数表示所有奶牛全都躲进牛棚所用的最少时间。如果无法使全部奶牛都躲进牛棚,输出 −1。
输入输出样例
输入 #1
3 4 7 2 0 4 2 6 1 2 40 3 2 70 2 3 90 1 3 120
输出 #1
110
-
题意
一张无向图上有n个点,每个点上有s[i]头牛,可以容纳p[i]头牛,如果有一条边(u,v,w)∈G,那么一头牛可以用w的时间从u到v
问至少需要多久时间可以使全部的牛躲进牛棚。
-
题解
看到让所有的牛进入牛棚,这个时间很明显是可以二分的。因为如果tt的时间所有的牛可以躲进,那么t′>tt′>t还有什么理由躲不进呢。
那么考虑这些时间有什么特点。假设我们用一个集合S来放所有的dis[i][j],那么如果有一个t∉S,那么如果t可行,S中第一个比它小的数字也同样可行。此时在检验这个数字纯粹是在浪费评测机资源 也不会慢多少
于是我们把所有的时间存进setset里,在放进一个数组,对这个数组进行二分,此时次数为log2(n^2)。
于是剩下的检验操作有手就行了。建两排点,一排为牛,另一排为牛棚。超级源点SS连到牛,流量为sisi,牛棚连到超级汇点T,流量为p[i],∀dis[i][j]≤mid的点,连一条从牛i连接到牛棚jj,流量+∞的边。跑一遍最大流,若flow=∑i=1nsi,则此方案可行
-
相信没有多少人喜欢上面的一通分析吧,那么,你们喜欢的代码来了—— -
代码
-
#include<bits/stdc++.h> using namespace std; const int maxn=4010,maxe=100010*2; #define int long long struct Graph{ struct node{ int v,w,nxt; }e[maxe<<1]; int head[maxn],cur[maxn],tot; int dis[maxn]; int s,t; void init(int _s,int _t){s=_s,t=_t;tot=1;memset(head,0,sizeof head);} Graph(int _s=0,int _t=0){init(_s,_t);} void add(int u,int v,int w){ //printf("%d %d %d\n",u,v,w); e[++tot]=(node){v,w,head[u]},head[u]=tot; e[++tot]=(node){u,0,head[v]},head[v]=tot; } #define v e[i].v inline bool bfs(){ queue<int>q; memset(dis,0,sizeof dis); memcpy(cur,head,sizeof head); dis[s]=1;q.push(s); while(q.size()){ int u=q.front();q.pop(); for(int i=head[u];i;i=e[i].nxt) if(!dis[v]&&e[i].w){ dis[v]=dis[u]+1,q.push(v); if(v==t)return true; } } return false; } int dfs(int u,int flow){ if(u==t)return flow; int rest=flow; for(int i=cur[u];i&&rest;i=e[i].nxt){ if(dis[v]==dis[u]+1&&e[i].w){ int tmp=dfs(v,min(rest,e[i].w)); rest-=tmp,e[i].w-=tmp,e[i^1].w+=tmp; } cur[u]=i; } if(rest==0)dis[u]=-1; return flow-rest; } #undef v int dinic(){ int ans=0; while(bfs()) while(int sth=dfs(s,2e9)) ans+=sth; return ans; } }; Graph G; int f[300][300]; int s[300],p[300]; int n,m,u,v;int w,sum; const int inf=199000000900; bool check(int x){ G.init(0,2*n+1); for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) if(f[i][j]<=x||i==j) G.add(i,j+n,inf); for(int i=1;i<=n;i++)G.add(G.s,i,s[i]),G.add(i+n,G.t,p[i]); int tmp=G.dinic(); return tmp>=sum; } set<int>a; vector<int>vec; signed main(){ memset(f,0x3f,sizeof f); scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%lld%lld",&s[i],&p[i]),sum+=s[i]; for(int i=1;i<=m;i++) scanf("%d%d%lld",&u,&v,&w), f[u][v]=f[v][u]=min(f[v][u],w); for(int k=1;k<=n;k++) for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) f[i][j]=min(f[i][j],f[i][k]+f[k][j]); for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) if(f[i][j]!=0x3f3f3f3f3f3f3f3f) a.insert(f[i][j]); vec.assign(a.begin(),a.end()); int l=0,r=vec.size()-1,ans=-1; for(;l<=r;){ int mid=l+r>>1; if(check(vec[mid]))ans=vec[mid],r=mid-1; else l=mid+1; }cout<<ans; }