【bzoj1570】Blue Mary的旅行

题意

  给定一张有向图,每条边每天最多经过有限次,一个人每天只能经过一条边, T 个人从1号点出发,问多少天之后能到达n

解法

分层图+最大流:
  一开始没有看见每一个人每天只能走一条边这个条件,所以就 WA 了很多次
  对每一天建一层图,并且上下两层之间要联通,然后每一层的 n 号点也要和汇点联通,那么我们可以对这个分层图求最大流,如果最大流T,显然经过的层数就是答案
  为了方便,我们可以枚举天数,逐天进行加边,每加完一天的边就跑一次最大流,如果如何条件,即是答案,否则复原原图,继续下一天

复杂度

O( ansn+mN2M

代码

#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<queue>
#define Lint long long int
using namespace std;
const int INF=0x3f3f3f3f;
const int MAXN=10010;
struct node
{
    int next,to,c;
}t[MAXN*100];
struct task
{
    int u,v,c;
}p[MAXN];
int head[MAXN],num;
int lev[MAXN];
int n,m,T,END;
queue<int> q;
void add(int u,int v,int c)
{
    t[++num]=(node){ head[u],v,c };
    head[u]=num;
}
bool bfs()
{
    int tmp;
    for(int i=0;i<=END;i++)   lev[i]=0;
    while( !q.empty() )   q.pop();
    q.push( 0 ),lev[0]=1;
    while( !q.empty() )
    {
        tmp=q.front(),q.pop();
        for(int i=head[tmp],x; i!=-1 ;i=t[i].next)
        {
            x=t[i].to;
            if( !lev[x] && t[i].c )   lev[x]=lev[tmp]+1,q.push( x );
        }
    }
    return lev[END];
}
int dfs(int k,int fm)
{
    if( k==END )   return fm;
    int tmp=0,f;
    for(int i=head[k],x; i!=-1 ;i=t[i].next)
    {
        x=t[i].to;
        if( lev[x]==lev[k]+1 && t[i].c )
        {
            f=dfs( x,min( fm-tmp,t[i].c ) );
            t[i].c-=f,t[i^1].c+=f,tmp+=f;
            if( tmp==fm )   break ;
        }
    }
    if( tmp<fm )   lev[k]=0;
    return tmp;
}
int Dinic()
{
    int F=0;
    while( bfs() )   F+=dfs( 0,INF );
    return F;
}
void modify()
{
    for(int i=0;i<=num;i+=2)   t[i].c+=t[i^1].c,t[i^1].c=0;
}
int main()
{
    int u,v,c;
    scanf("%d%d%d",&n,&m,&T);
    END=(n+T+1)*n+1;
    for(int i=0;i<=END;i++)   head[i]=num=-1;
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d%d",&u,&v,&c);
        p[i]=(task){ u,v,c };
    }
    add( 0,1,T ),add( 1,0,0 );
    for(int i=1;i<=n+T;i++)
    {
        modify();
        for(int j=1;j<=m;j++)   add( (i-1)*n+p[j].u,i*n+p[j].v,p[j].c ),add( i*n+p[j].v,(i-1)*n+p[j].u,0 );
        for(int j=1;j<=n;j++)   add( (i-1)*n+j,i*n+j,INF ),add( i*n+j,(i-1)*n+j,0 );
        add( i*n+n,END,T ),add( END,i*n+n,0 );
        if( Dinic()==T )   { printf("%d\n",i);break ; }
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值