hdu4807 费用流

来源:互联网 发布:电子称数据输出到电脑 编辑:程序博客网 时间:2024/04/29 04:12
F - Lunch Time
Time Limit:2000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u
Submit Status

Description

The campus of Nanjing University of Science and Technology can be viewed as a graph with N vertexes and M directed edges (vertexes are numbered from 0 to N - 1). Each edge has the same length 1. Every day, there are K students walking to the dinning-hall (vertex N - 1) from the teaching building (vertex 0) at lunch time. They all want reach the dinning-hall as soon as possible. However, each edge can only serve at most ci students at any time. Can you make arrangements for students, so that the last student can reach the dinning-hall as soon as possible? (It is assumed that the speed of the students is 1 edge per unit time)

Input

There are several test cases, please process till EOF. 
The first line of each test case contains three integer N(2 <= N <= 2500), M(0 <= M <= 5000), K(0 <= K <= 10 9). Then follows M lines, each line has three numbers a i, b i, c i(0 <= c i <= 20), means there is an edge from vertex a i to b i with the capacity c i.

Output

For each test case, print an integer represents the minimum time. If the requirements can not be met, print “No solution”(without quotes) instead.

Sample Input

5 6 40 1 20 3 11 2 12 3 11 4 13 4 23 3 100 1 11 2 10 2 12 0 1

Sample Output

36

No solution

题意:南京大学是一个图,有n个点,学生要从0点到n-1点,每条路径长度为1,每条路径可以通过的人数有一个上限ci

学生单位时间走得路长度为1,现在有k个人要从0点到n-1点,问最少时间是多少

从0点走到n-1点用的时间就是路程长度,从0到n-1有多条路径可以走,我们尽量走最短的路程,假如走过一条路径用时间为t,一次可以通过p个人,那么t时刻后每单位时间在这条路径都可以通过p个人,我们用费用流求出每条路径的长度以及每条路径最多可以同时通过的人数,然后保存到数组当中,然后二分时间,即可;

#include <iostream>#include <stdio.h>#include <string.h>#include <algorithm>#include <queue>using namespace std;typedef long long LL;const LL MAXN=100110;const LL MAXM=4000110;const LL INF=0x3f3f3f3f;struct Node{    LL to,next,cap,flow,cost;} edge[MAXM];LL tol;LL head[MAXN];LL gap[MAXN],dis[MAXN],pre[MAXN],cur[MAXN];LL dim[MAXN],tim[MAXN],tot;void init(){    tol=0;    tot=0;    memset(head,-1,sizeof(head));}void addedge(LL u,LL v,LL w,LL rw=0){    edge[tol].to=v;    edge[tol].cap=w;    edge[tol].next=head[u];    edge[tol].flow=0;    edge[tol].cost=1;    head[u]=tol++;    edge[tol].to=u;    edge[tol].cap=rw;    edge[tol].next=head[v];    edge[tol].flow=0;    edge[tol].cost=-1;    head[v]=tol++;}LL N;bool vis[MAXN];LL spfa(LL s,LL t){    queue<LL>que;    for(int i=0; i<N; i++)    {        dis[i]=INF;        vis[i]=false;        pre[i]=-1;    }    dis[s]=0;    vis[s]=true;    que.push(s);    while(!que.empty())    {        LL u=que.front();        que.pop();        vis[u]=false;        for(int i=head[u]; i!=-1; i=edge[i].next)        {            int v=edge[i].to;            if(edge[i].cap>edge[i].flow&&dis[v]>dis[u]+edge[i].cost)            {                dis[v]=dis[u]+edge[i].cost;                pre[v]=i;                if(!vis[v])                {                    vis[v]=true;                    que.push(v);                }            }        }    }    return pre[t];}void solve(LL s,LL t){    LL flow=0,cost=0,D;    while(1)    {        D=spfa(s,t);        if(D==-1)            break;        dim[tot]=dis[t];///当前路径最短时间        LL Min=INF;        for(int i=pre[t]; i!=-1; i=pre[edge[i^1].to])        {            if(Min>edge[i].cap-edge[i].flow)            {                Min=edge[i].cap-edge[i].flow;            }        }        tim[tot++]=Min;///当前路径一次性可以通过的最多人数        for(int i=pre[t]; i!=-1; i=pre[edge[i^1].to])        {            edge[i].flow+=Min;            edge[i^1].flow-=Min;        }    }}int main(){    LL n,m,k;    LL u,v,c;    while(scanf("%lld%lld%lld",&n,&m,&k)!=-1)    {        init();        N=n;        for(LL i=0; i<m; i++)        {            scanf("%lld%lld%lld",&u,&v,&c);            addedge(u,v,c);        }        solve(0,n-1);        if(k==0)        {            printf("0\n");            continue;        }        if(tot==0)///如果路径条数为0,直接不可能到达n-1点        {            printf("No solution\n");            continue;        }        LL l=0,r=1e9,mid,ans;        int flag=0;        while(l<=r)        {            mid=(r+l)/2;            ans=0;            for(LL i=0; i<tot; i++)            {                if(dim[i]<=mid)                {                    ans+=(mid-dim[i])*tim[i]+ tim[i];///在mid时间,大于dim[i]的时间里每单位时间有tim[i]个人通过,然后加上dim[i]时刻那第一波人数                }            }            if(ans>=k)            {                flag=1;                r=mid-1;            }            else                l=mid+1;        }        if(flag==0)        {            printf("No solution\n");            continue;        }        printf("%lld\n",l);    }    return 0;}




0 0
原创粉丝点击