约定:
2 <= N <= 50
1 <= M <= 2450
1 <= T <= 50
1 <= X,Y <= N
X != Y
1 <= Z <= 50
做过紧急疏散这个题就是一眼题了,考虑二分答案然后按时间拆点用判满流来check即可;
注意二分大上界为n+tot,因为tot个人排队走即可,一开始设为n*tot狂T不止;
//MADE BY QT666
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;
typedef long long ll;
const int N=200050;
const int Inf=19260817;
int head[N],to[N],nxt[N],s[N],S,T,cnt=1,level[N],vis[N],q[N*10],F,n,m,tot;
void Addedge(int x,int y,int z) {
    to[++cnt]=y,s[cnt]=z,nxt[cnt]=head[x],head[x]=cnt;
}
void lnk(int x,int y,int z){
    Addedge(x,y,z);Addedge(y,x,0);
}
bool bfs(){
    for(int i=S;i<=T;i++) level[i]=0,vis[i]=0;
    int t=0,sum=1;
    q[0]=S,level[S]=1,vis[S]=1;
    while(t<sum){
	int now=q[t++];
	if(now==T) return 1;
	for(int i=head[now];i;i=nxt[i]){
	    int y=to[i];
	    if(level[y]==0&&s[i]){
		level[y]=level[now]+1;
		q[sum++]=y;
	    }
	}
    }
    return 0;
}
int dfs(int now,int maxf){
    if(now==T) return maxf;
    int ret=0;
    for(int i=head[now];i;i=nxt[i]) {
	int y=to[i],f=s[i];
	if(level[y]==level[now]+1&&f) {
	    int minn=min(maxf-ret,f);
	    f=dfs(y,minn);
	    s[i]-=f;s[i^1]+=f;ret+=f;
	    if(ret==maxf) break;
	}
    }
    if(!ret) level[now]=0;
    return ret;
}
void Dinic(){
    while(bfs()) F+=dfs(S,Inf);
}
struct data{
    int to,lim;
};
vector<data> p[100];
struct date{
    int id[2505];
}g[100];
bool check(int mid){
    memset(head,0,sizeof(head));cnt=1;int tt=0;
    for(int i=1;i<=n;i++){
	for(int j=0;j<=mid;j++) g[i].id[j]=++tt;
    }
    S=0,T=tt+1;
    for(int i=1;i<=n;i++){
	for(int j=0;j<p[i].size();j++){
	    int x=p[i][j].to,lim=p[i][j].lim;
	    for(int k=0;k<mid;k++){
		lnk(g[i].id[k],g[x].id[k+1],lim);
	    }
	}
	for(int k=0;k<mid;k++) lnk(g[i].id[k],g[i].id[k+1],Inf);
    }
    lnk(S,g[1].id[0],tot);
    for(int i=0;i<=mid;i++) lnk(g[n].id[i],T,Inf);
    F=0;Dinic();
    return F==tot; 
}
int main(){
    scanf("%d%d%d",&n,&m,&tot);
    for(int i=1;i<=m;i++){
	int x,y,z;scanf("%d%d%d",&x,&y,&z);
	p[x].push_back((data){y,z});
    }
    int l=0,r=n+tot,ans=0;
    while(l<=r){
	int mid=(l+r)>>1;
	if(check(mid)) r=mid-1,ans=mid;
	else l=mid+1;
    }
    printf("%d\n",ans);
    return 0;
}
bzoj 1570: [JSOI2008]Blue Mary的旅行
原文:http://www.cnblogs.com/qt666/p/7625201.html