1. 程式人生 > >BZOJ4669搶奪(費用流+二分答案)

BZOJ4669搶奪(費用流+二分答案)

題目描述

大戰將至, 美國決定實行計劃經濟。美國西部總共有 N 個城市,編號 為 0 ∼ N − 1,以及 M 條道路,道路是單向的。其中城市 0 是一個大城 市,裡面住著 K 個人,而城市 N − 1 是一個農業城市。現在所有城市 0 的 居民都需要到城市 N − 1 去領取食物。由於擔心體力不支,所以居民都會 採取開車的形式出行。但道路不是無限寬的,對於一條道路,會有 ci 的限 制,表示在同一天內,最多隻能有 ci 輛車同時在這條道路上行駛。一條道 路的長度為 1,每輛車的行駛速度也可以假定為 1 每天。城市 N − 1 會在 每個居民都到達後馬上開始發放食物。現在 Reddington 想知道,假如在最 優安排下,居民最早能在多少天后領到食物。假如沒有居民那就不需要發 放食物,預設為第 0 天。 題解
ORZ zyz 首先答案具有單調性,可以二分。 然後貪心一波,我們肯定要撿著最短路去走,然後我們增廣出了一條路,因為時間時固定的,所以我們能通過的人數已經確定了。 就是(T-dis+1)*min(l)前面的是第一波人到終點到結束的時間, minl表示路徑權值的最小值。 然後我們就一直重複這個過程,發現這個過程和EK費用流完全一樣。 程式碼
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#define
inf 1e18 #define N 1009 #define M 20002 using namespace std; typedef long long ll; queue<int>q; int dis[N],head[N],tot=1,pre[N],n,m,k; ll fl[N],num; bool vis[N]; inline int rd(){ int x=0;char c=getchar();bool f=0; while(!isdigit(c)){if(c=='-')f=1;c=getchar();} while(isdigit(c)){x=(x<<1
)+(x<<3)+(c^48);c=getchar();} return f?-x:x; } struct edge{int n,to,l,f;}e[M]; inline void add(int u,int v,int l,int f){ e[++tot].n=head[u];e[tot].to=v;head[u]=tot;e[tot].l=l;e[tot].f=f; e[++tot].n=head[v];e[tot].to=u;head[v]=tot;e[tot].l=0;e[tot].f=-f; } inline bool spfa(int s,int t){ memset(dis,0x3f,sizeof(dis)); dis[s]=0;q.push(s);fl[s]=inf; while(!q.empty()){ int u=q.front();q.pop();vis[u]=0; for(int i=head[u];i;i=e[i].n){ int v=e[i].to; if(e[i].l&&dis[v]>dis[u]+e[i].f){ dis[v]=dis[u]+e[i].f;pre[v]=i;fl[v]=min(fl[u],1ll*e[i].l); if(!vis[v]){vis[v]=1;q.push(v);} } } } return dis[t]!=0x3f3f3f3f; } struct node{ int u,v,w; }a[M]; inline void calc(int s,int t,ll mid){ int x=t; while(x!=s){ int i=pre[x]; e[i].l-=fl[t];e[i^1].l+=fl[t];x=e[i^1].to; } num+=max(0ll,1ll*(mid-dis[t]+1)*fl[t]); } inline bool check(ll mid){ memset(head,0,sizeof(head));tot=1;num=0; for(int i=1;i<=m;++i)add(a[i].u,a[i].v,a[i].w,1); while(spfa(0,n-1))calc(0,n-1,mid); return num>=k; } int main(){ while(scanf("%d%d%d",&n,&m,&k)!=EOF){ for(int i=1;i<=m;++i){a[i].u=rd();a[i].v=rd();a[i].w=rd();} ll l=0,r=1e12,ans=-1; while(l<=r){ ll mid=(l+r)>>1; if(check(mid)){ ans=mid;r=mid-1; }else l=mid+1; } if(~ans)printf("%d\n",ans);else printf("No solution\n"); } return 0; }