HDU 4807 Lunch Time(费用流)

题意:

有k个人要从教室走到食堂,但是这两点之间的路的承载能力是有限的,所以如何走,能够让最后一个人到达食堂的时间尽量小。题意很清晰,恩,然并卵。
刚看肯定觉得是最大流或者是费用流,但是这两者都无法从时间上来考虑,也就是会忽略掉第一拨人到达终点的时间,所以是不行的。
但是有一点我们是需要知道的,那就是费用流是通过最短路径来增广的,而且有一个很重要的性质就是每一次找到的最短路的长度是上升的,
而在本题中,长度就是时间,所以我们可以通过费用流来枚举所能找到的最短路,当找到新的一条之后,我们要考虑一个事情就是第一波经过
这条路的人是肯定要考虑的,但是是否需要找新的一条路或者是仅仅靠已经找到的路来承载所有的人呢。为什么要考虑这个,因为有可能有的路
很长,有的路很短,那我们宁愿等也不会去走那条长的路。当一条路满流之后,其后的每一分钟都可以通过这条路流量的人数。总的来说,就
是这两个问题,搞懂之后就能做了,如果还是不懂的话,可以看这个:戳这里

代码:

//
//  Created by  CQU_CST_WuErli
//  Copyright (c) 2016 CQU_CST_WuErli. All rights reserved.
//
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <cctype>
#include <cmath>
#include <string>
#include <vector>
#include <list>
#include <map>
#include <queue>
#include <stack>
#include <set>
#include <algorithm>
#include <sstream>
#define CLR(x) memset(x,0,sizeof(x))
#define OFF(x) memset(x,-1,sizeof(x))
#define MEM(x,a) memset((x),(a),sizeof(x))
#define BUG cout << "I am here" << endl
#define lookln(x) cout << #x << "=" << x << endl
#define SI(a) scanf("%d",&a)
#define SII(a,b) scanf("%d%d",&a,&b)
#define SIII(a,b,c) scanf("%d%d%d",&a,&b,&c)
#define rep(flag,start,end) for(int flag=start;flag<=end;flag++)
#define Rep(flag,start,end) for(int flag=start;flag>=end;flag--)
#define Lson l,mid,rt<<1
#define Rson mid+1,r,rt<<1|1
#define Root 1,n,1
#define BigInteger bign
const int MAX_L=2005;// For BigInteger
const int INF_INT=0x3f3f3f3f;
const long long INF_LL=0x7fffffff;
const int MOD=1e9+7;
const double eps=1e-9;
const double pi=acos(-1);
typedef long long  ll;
using namespace std;

inline int read() {
    char c = getchar();
    while(!isdigit(c)) c = getchar();
    int x = 0;
    while(isdigit(c)) {
        x = x * 10 + c - '0';
        c = getchar();
    }
    return x;
}

const int N=5050;
int n,m,k;
int pnt[N<<1],nxt[N<<1],head[N],cap[N<<1],cost[N<<1],pre[N<<1];
int cnt;

void add_edge(int u,int v,int f,int c) {
    pnt[cnt]=v;pre[cnt]=u;nxt[cnt]=head[u];
    cap[cnt]=f;cost[cnt]=c;head[u]=cnt++;
}

int a[N],d[N],vis[N],p[N];

bool spfa(int s,int t,int &Flow,ll& Cost) {
    CLR(a);CLR(vis);
    rep(i,s,t) d[i]=INF_INT;
    queue<int> q;
    vis[s]=1;
    a[s]=INF_INT;
    d[s]=0;
    q.push(s);
    while (q.size()) {
        int x=q.front();q.pop();
        vis[x]=0;
        for (int i=head[x];~i;i=nxt[i]) {
            int v=pnt[i];
            if (d[v]>d[x]+cost[i] && cap[i]) {
                d[v]=d[x]+cost[i];
                p[v]=i;
                a[v]=min(a[x],cap[i]);
                if (!vis[v]) {
                    q.push(v);
                    vis[v]=1;
                }
            }
        }
    }
    if (d[t]>=INF_INT) return false;
    Flow+=a[t];
    Cost+=d[t];
    for (int u=t;u!=s;u=pre[p[u]]) {
        cap[p[u]]-=a[t];
        cap[p[u]^1]+=a[t];
    }
    return true;
}

ll MFMC(int s,int t) {
    int Flow=0;
    ll Cost=0;
    int ans=INF_INT;
    int sump=k;
    int nowp=0;
    int cur=0;
    while (spfa(s,t,Flow,Cost)) {
        sump-=(d[t]-cur)*nowp+a[t];
        cur=d[t];nowp+=a[t];
        int tmp=d[t]+(sump<=0?0:sump)/nowp+((sump<=0?0:sump)%nowp?1:0);
        ans=min(ans,tmp);
        if (sump<=0) break;
    }
    return ans;
}
int main(int argc, char const *argv[]) {
#ifdef LOCAL
    freopen("C:\\Users\\john\\Desktop\\in.txt","r",stdin);
    // freopen("C:\\Users\\john\\Desktop\\out.txt","w",stdout);
#endif
    while(SIII(n,m,k)==3) {
        OFF(head);cnt=0;
        rep(i,1,m) {
            int u,v,c;
            u=read();v=read();c=read();
            // cout << u << ' ' << v <<  ' ' << c << endl;
            u++,v++;
            add_edge(u,v,c,1);
            add_edge(v,u,0,-1);
        }
        int ans;
        if (k==0) ans=0;
        else ans=MFMC(1,n);
        if (ans>=INF_INT) puts("No solution");
        else printf("%d\n",ans);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值