HDU-4807-Lunch Time(二分+费用流,思维)
这道题非常好,如果没有真正弄懂费用流算法的人,只会套模版的人是肯定做不出来的。
我们其实这样考虑,费用流真正的思想是吧费用作为长度,然后跑最短路,同时保证路上的流量不为0,也就是增广;
跑到终点后,回溯把路上的流量进行修改。一直这样下去直到无法增广。
这道题也是一样,我们把路径长度看成费用,路径限制看成流量限制。
每次增广到终点后,得到的dis[t]代表源点到汇点的路径长度,incf[t]代表的是这条路上的流量限制。
每一次增广成功,我们都会获得一个和之前不同的路径。
这样我们就能够得到所有s-t路径长度,以及长度对应的流量限制。并且他们所有路径都是满足在流量限制条件下的。
然后其实就很简单了,我们知道我们需要运输的人数,同时知道每一条路径对应的路径的路径运输能力和路径长度,那么我们对答案进行二分,也就是对总共用的时间进行二分。
对于所有路径长度是>=总共运输时间的(每次速度为1),也就是说对于当前的时间内,这条路是可以运载一些人到终点的,那么这条路运输的人数其实就是 e[i].flow*(t-e[i].dist+1)
也就是当前道路的流量*(所用的时间-从起点到终点的时间+1),因为当前道路的在前dist-1的时间内,人还在路上,没有抵达,在dist时间以后,人会源源不断的来到。
注意k可能是0,需要先特判k=0,再特判最大流量=0。不然会错。。。
#include<iostream> #include<stdio.h> #include<algorithm> #include<string.h> #include<queue> #define LL long long using namespace std; const int maxx = 2e5+6; const LL INF = 1e18; int ver[maxx],head[maxx],Next[maxx]; LL incf[maxx]; LL cost[maxx],edge[maxx]; int v[maxx],pre[maxx]; LL d[maxx]; int tot,cnt,n,m,s,t; LL ans,k,maxflow; struct node { LL flow; LL w; } a[maxx]; void add(int x,int y,LL z,LL c) { ver[++tot]=y; edge[tot]=z; cost[tot]=c; Next[tot]=head[x]; head[x]=tot; ver[++tot]=x; edge[tot]=0; cost[tot]=-c; Next[tot]=head[y]; head[y]=tot; } bool spfa() { queue<int>q; while(q.size())q.pop(); for (int i=1; i<=n+5; i++) { d[i]=INF; v[i]=0; } q.push(s); d[s]=0; v[s]=1; incf[s]=INF; while(q.size()) { int x=q.front(); v[x]=0; q.pop(); for (int i=head[x]; i; i=Next[i]) { if (!edge[i]) continue; int y=ver[i]; //cout<<x<<" "<<y<<" "<<edge[i]<<endl; if(d[y]>d[x]+cost[i]) { d[y]=d[x]+cost[i]; incf[y]=min(incf[x],edge[i]); pre[y]=i; if(!v[y])v[y]=1,q.push(y); } } } if(d[t]==INF)return false; else return true; } void update() { int x=t; cnt++; a[cnt].w=d[t]; // cout<<t-1<<"---"<<incf[t]<<"--"<<d[t]<<endl; a[cnt].flow=incf[t]; while(x!=s) { int i=pre[x]; edge[i]-=incf[t]; edge[i^1]+=incf[t]; x=ver[i^1]; // printf("%d-->",x-1); } // cout<<endl; maxflow+=incf[t]; } bool check(LL x) { LL sum=0; for (int i=1; i<=cnt; i++) { if (a[i].w<=x) { sum+=(LL)a[i].flow*(x-a[i].w+1); } } return sum>=k; } int main() { int uu,vv,c; while(~scanf("%d%d%lld",&n,&m,&k)) { cnt=0; tot=1; maxflow=0; s=1; t=n; memset(head,0,sizeof(head)); for (int i=1; i<=m; i++) { scanf("%d%d%d",&uu,&vv,&c); add(uu+1,vv+1,c,1); } while(spfa())update(); if (k==0) { printf("0\n"); } else if (maxflow==0){ printf("No solution\n"); }else { int l=1,r=1e9; while(l<=r) { int mid=(l+r)>>1; if (check(mid)) { r=mid-1; ans=mid; } else { l=mid+1; } } printf("%lld\n",ans); } } return 0; }
有不懂欢迎咨询
QQ:1326487164(添加时记得备注)