#网络流,分层图#洛谷 4400 [JSOI2008] Blue Mary的旅行

题目


分析

考虑答案一定最大不超过\(n\),那么可以建分层图,
若当前最大流等于\(n\),直接输出枚举的天数
\((x,x')\)容量为\(inf\)\((x,y')\)容量为一个航班最多的票数
然后\(n'\)与汇点连一条边,容量为总人数(\(x'\)表示当前层,\(x\)表示上一层)


代码

#include <cstdio>
#include <cctype>
#include <queue>
#define rr register
using namespace std;
const int N=2511,inf=0x3f3f3f3f; struct node{int y,w,next;}e[N<<8];
int as[N<<1],rk[101][51],n,k=1,Tot,m,X[N],Y[N],Z[N],dis[N<<1],total,s,t,now,ans;
inline signed iut(){
	rr int ans=0; rr char c=getchar();
	while (!isdigit(c)) c=getchar();
	while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
	return ans;
}
inline void add(int x,int y,int w){
	e[++k]=(node){y,w,as[x]}; as[x]=k;
	e[++k]=(node){x,0,as[y]}; as[y]=k;
}
inline bool bfs(int s){
    for (rr int i=1;i<=Tot;++i) dis[i]=0;
    rr queue<int>q; q.push(s); dis[s]=1;
    while (q.size()){
        rr int x=q.front(); q.pop();
        for (rr int i=as[x];i;i=e[i].next)
        if (e[i].w>0&&!dis[e[i].y]){
            dis[e[i].y]=dis[x]+1;
            if (e[i].y==t) return 1;
            q.push(e[i].y);
        }
    }
    return 0;
}
inline signed dfs(int x,int now){
    if (x==t||!now) return now;
    rr int rest=0,f;
    for (rr int i=as[x];i;i=e[i].next)
    if (e[i].w>0&&dis[e[i].y]==dis[x]+1){
        rest+=(f=dfs(e[i].y,min(now-rest,e[i].w)));
        e[i].w-=f; e[i^1].w+=f;
        if (now==rest) return rest;
    }
    if (!rest) dis[x]=0;
    return rest;
}
signed main(){
	n=iut(),m=iut(),total=iut(),s=1,Tot=t=2;
	for (rr int i=1;i<=n;++i) rk[0][i]=++Tot;
	add(s,rk[0][1],total),add(rk[0][n],t,total);
	for (rr int i=1;i<=m;++i) X[i]=iut(),Y[i]=iut(),Z[i]=iut();
	for (ans=1;;++ans){
		for (rr int i=1;i<=n;++i) add(rk[ans-1][i],rk[ans][i]=++Tot,inf);
		for (rr int i=1;i<=m;++i) add(rk[ans-1][X[i]],rk[ans][Y[i]],Z[i]);
		add(rk[ans][n],t,total);
		while (bfs(s)) now+=dfs(s,inf);
		if (now==total) break;
	}
    return !printf("%d",ans);
}
posted @ 2020-08-18 21:15  lemondinosaur  阅读(105)  评论(0编辑  收藏  举报