地震逃生【网络流】

##题目大意:
mm个人要从11nn,每条路最多能过p[i]p[i]个人,求每次最多能过几个人,需要几次才能使全部人通过?


##思路:
很裸的最大流。源点连向点11,点nn连向汇点,按照读入的数据建模,跑一边DinicDinic即可。


##代码:

#include <iostream>
#include <cstdio>
#include <queue>
#include <cstring>
#define Inf 0x7f
#define INF 2147483647
using namespace std;

int n,m,peo,k,head[100001],dep[1001],x,y,z,ans,sum,s,t;

struct edge
{
    int next,to,c;
}e[100001];

void add(int from,int to,int c)  //建模
{
    k++;
    e[k].c=c;
    e[k].to=to;
    e[k].next=head[from];
    head[from]=k;
}

bool bfs()  //分层
{
    memset(dep,0x3f,sizeof(dep));
    dep[s]=0;
    queue<int> q;
    q.push(s);
    while (q.size())
    {
        int u=q.front();
        q.pop();
        for (int i=head[u];i;i=e[i].next)
        {
            int v=e[i].to;
            if (dep[v]>dep[u]+1&&e[i].c)  
            {
                dep[v]=dep[u]+1;
                q.push(v);
            }
        }
    }
    return (dep[t]<0x3f3f3f3f);
}

int dfs(int u,int low)  //找增广路
{
    int lows=0;
    if (u==t) return low;
    for (int i=head[u];i;i=e[i].next)
    {
        int v=e[i].to;
        if (dep[v]==dep[u]+1&&e[i].c)
        {
            lows=dfs(v,min(low,e[i].c));  //找最小流量
            if (!lows) continue;
            e[i].c-=lows;  //正向边
            e[i^1].c+=lows;  //反向边
            return lows;
        }
    }
    return 0;
}

int main()
{
    scanf("%d%d%d",&n,&m,&peo);
    k=1;
    s=999;
    t=998;
    add(s,1,INF);
    add(1,s,0);
    add(n,t,INF);
    add(t,n,0);
    for (int i=1;i<=m;i++)
    {
        scanf("%d%d%d",&x,&y,&z);
        add(x,y,z);
        add(y,x,0);
    }
    while (bfs())
    {
        while (sum=dfs(s,INF))
         ans+=sum;
    }
    if (!ans) return printf("Orz Ni Jinan Saint Cow!")&0;
    if (peo%ans) printf("%d %d",ans,peo/ans+1);
     else printf("%d %d",ans,peo/ans);
    return 0;
}
posted @ 2018-08-11 11:11  全OI最菜  阅读(87)  评论(0编辑  收藏  举报