bzoj 4669 抢夺 Posted on 2019-05-30 | Views: 二分答案 + 费用流. 答案显然可以二分,只需要如何验证一个答案 $mid$ 是否合法. 考虑第一波同时出发的人,他们会选择最优的路径,而后来的人选择的路径必定与他们相同. 于是可以通过增广计算出在 $mid$ 天内到达的人数.而退流操作对应的贡献也是正确的,所以不需要另外考虑. 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134#include<bits/stdc++.h>using namespace std;typedef long long ll;inline int read(){ int out=0,fh=1; char jp=getchar(); while ((jp>'9'||jp<'0')&&jp!='-') jp=getchar(); if (jp=='-') fh=-1,jp=getchar(); while (jp>='0'&&jp<='9') out=out*10+jp-'0',jp=getchar(); return out*fh;}const int MAXN=1e4+10;const int inf=1e9;int ecnt=-1,head[MAXN];struct edge{ int nx,to,flow,dis;}E[MAXN];void addedge(int u,int v,int flow,int dis){ ++ecnt; E[ecnt].nx=head[u]; E[ecnt].to=v; E[ecnt].flow=flow; E[ecnt].dis=dis; head[u]=ecnt;}void ins(int u,int v,int flow,int dis){ addedge(u,v,flow,dis); addedge(v,u,0,-dis);}int n,m,k;int dis[MAXN],flow[MAXN],pre[MAXN],lst[MAXN],vis[MAXN];queue<int> q;bool spfa(int S,int T){ while(!q.empty()) q.pop(); for(int i=1;i<=n;++i) { vis[i]=0; flow[i]=inf; dis[i]=inf; } pre[T]=-1; vis[S]=1; dis[S]=0; q.push(S); while(!q.empty()) { int u=q.front(); q.pop(); vis[u]=0; for(int i=head[u];i!=-1;i=E[i].nx) { int v=E[i].to; if(E[i].flow>0 && dis[v]>dis[u]+E[i].dis) { dis[v]=dis[u]+E[i].dis; flow[v]=min(flow[u],E[i].flow); pre[v]=u; lst[v]=i; if(!vis[v]) { vis[v]=1; q.push(v); } } } } return pre[T]!=-1;}int Dist[MAXN],Flow[MAXN],tot=0;int mcmf(int S,int T){ while(spfa(S,T)) { int now=T; while(now!=S) { E[lst[now]].flow-=flow[T]; E[lst[now]^1].flow+=flow[T]; now=pre[now]; } ++tot; Dist[tot]=dis[T]; Flow[tot]=flow[T]; }}void init(){ memset(head,-1,sizeof head); ecnt=-1; tot=0;}bool check(int mid){ ll tmp=k; for(int i=1;i<=tot && tmp>0;++i) tmp-=1LL*(mid-Dist[i]+1)*Flow[i]; return tmp<=0;}int main(){ while(~scanf("%d%d%d",&n,&m,&k)) { init(); for(int i=1;i<=m;++i) { int u=read()+1,v=read()+1,c=read(); ins(u,v,c,1); } mcmf(1,n); int ans=-1,L=0,R=n+k+1; while(L<=R) { int mid=(L+R)>>1; if(check(mid)) ans=mid,R=mid-1; else L=mid+1; } if(ans==-1) puts("No solution"); else printf("%d\n",ans); } return 0;}