EOJ Monthly 2020.3迷宫 (分层图思想)
题:https://acm.ecnu.edu.cn/contest/255/problem/A/
题意:有m个人在点S,要全部走的点T,题目给定每条通道每天只能走的人数,问最少几天能完成。
分析:这和最大流的水流问题很相似,只不过最大流的水流是一直会占这某一通道的,而这里只是占用了单位时间;
我们考虑二分天数,因为天数越多,能全到终点的可能性越大,所以具有单调性。接着依据所二分的天数,分成n层图,相邻天数相邻节点连边,判断最大流是否满足即可。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<bits/stdc++.h> using namespace std; const int M=4e5+5; const int N=5500; const int inf=0x3f3f3f3f; int tot,s,t; struct node{ int u,v,nextt; int w; }e[M<<1]; vector<node>g[M]; int head[N],deep[N],cur[N]; void addedge(int u,int v,int w){ e[tot].v=v; e[tot].w=w; e[tot].nextt=head[u]; head[u]=tot++; e[tot].v=u; e[tot].w=0; e[tot].nextt=head[v]; head[v]=tot++; } bool bfs(){ for(int i=0;i<=t;i++) deep[i]=0; queue<int>que; que.push(s); deep[s]=1; while(!que.empty()){ int u=que.front(); que.pop(); for(int i=head[u];~i;i=e[i].nextt){ int v=e[i].v; if(e[i].w>0&&deep[v]==0){ deep[v]=deep[u]+1; if(v==t) return true; que.push(v); } } } return deep[t]!=0; } int dfs(int u,int fl){ if(u==t) return fl; int ans=0,x=0; for(int i=cur[u];~i;i=e[i].nextt){ int v=e[i].v; if(e[i].w>0&&deep[v]==deep[u]+1){ x=dfs(v,min(fl-ans,e[i].w)); e[i].w-=x; e[i^1].w+=x; ans+=x; if(ans==fl) return ans; if(e[i].w) cur[u]=i; } } if(ans==0) deep[u]=0; return ans; } int dinic(){ int res=0; while(bfs()){ for(int i=0;i<=t;i++) cur[i]=head[i]; res+=dfs(s,inf); } return res; } int main(){ int num,n,m,S,T,minn=0; scanf("%d%d%d%d%d",&num,&n,&m,&S,&T); for(int u,v,w,i=1;i<=m;i++){ scanf("%d%d%d",&u,&v,&w); g[u].push_back(node{u,v,0,w}); } int l=1,r=100; while(l<=r){ int x=(l+r)>>1; /// cout<<x<<"!!"<<endl; tot=0; s=S,t=T+x*n; memset(head,-1,sizeof(head)); for(int i=1;i<=n;i++) for(auto pv:g[i]){ int u=pv.u,v=pv.v,w=pv.w; for(int j=1;j<=x;j++) addedge(u+(j-1)*n,v+j*n,w); } for(int i=1;i<=n;i++) for(int j=1;j<=x;j++) addedge(i+(j-1)*n,i+j*n,inf); if(dinic()>=num) minn=x,r=x-1; else l=x+1; } printf("%d\n",minn); return 0; }