HDU-4807-Lunch Time(二分+费用流,思维)

  这道题非常好,如果没有真正弄懂费用流算法的人,只会套模版的人是肯定做不出来的。

  我们其实这样考虑,费用流真正的思想是吧费用作为长度,然后跑最短路,同时保证路上的流量不为0,也就是增广;

  跑到终点后,回溯把路上的流量进行修改。一直这样下去直到无法增广。

  这道题也是一样,我们把路径长度看成费用,路径限制看成流量限制。

  每次增广到终点后,得到的dis[t]代表源点到汇点的路径长度,incf[t]代表的是这条路上的流量限制。

  每一次增广成功,我们都会获得一个和之前不同的路径。

  这样我们就能够得到所有s-t路径长度,以及长度对应的流量限制。并且他们所有路径都是满足在流量限制条件下的。

  然后其实就很简单了,我们知道我们需要运输的人数,同时知道每一条路径对应的路径的路径运输能力和路径长度,那么我们对答案进行二分,也就是对总共用的时间进行二分。

  对于所有路径长度是>=总共运输时间的(每次速度为1),也就是说对于当前的时间内,这条路是可以运载一些人到终点的,那么这条路运输的人数其实就是  e[i].flow*(t-e[i].dist+1)

 也就是当前道路的流量*(所用的时间-从起点到终点的时间+1),因为当前道路的在前dist-1的时间内,人还在路上,没有抵达,在dist时间以后,人会源源不断的来到。

注意k可能是0,需要先特判k=0,再特判最大流量=0。不然会错。。。

#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<queue>
#define LL long long
using namespace std;
const int maxx = 2e5+6;
const LL INF = 1e18;
int ver[maxx],head[maxx],Next[maxx];
LL incf[maxx];
LL cost[maxx],edge[maxx];
int v[maxx],pre[maxx];
LL d[maxx];
int tot,cnt,n,m,s,t;
LL ans,k,maxflow;
struct node
{
    LL flow;
    LL w;
} a[maxx];
void add(int x,int y,LL z,LL c)
{
    ver[++tot]=y;
    edge[tot]=z;
    cost[tot]=c;
    Next[tot]=head[x];
    head[x]=tot;
    ver[++tot]=x;
    edge[tot]=0;
    cost[tot]=-c;
    Next[tot]=head[y];
    head[y]=tot;
}
bool spfa()
{
    queue<int>q;
    while(q.size())q.pop();
    for (int i=1; i<=n+5; i++)
    {
        d[i]=INF;
        v[i]=0;
    }
    q.push(s);
    d[s]=0;
    v[s]=1;
    incf[s]=INF;
    while(q.size())
    {
        int x=q.front();
        v[x]=0;
        q.pop();
        for (int i=head[x]; i; i=Next[i])
        {
            if (!edge[i])
                continue;
            int y=ver[i];
            //cout<<x<<" "<<y<<" "<<edge[i]<<endl;
            if(d[y]>d[x]+cost[i])
            {
                d[y]=d[x]+cost[i];
                incf[y]=min(incf[x],edge[i]);
                pre[y]=i;
                if(!v[y])v[y]=1,q.push(y);
            }
        }
    }
    if(d[t]==INF)return false;
    else return true;
}
void update()
{
    int x=t;
    cnt++;
    a[cnt].w=d[t];
  //  cout<<t-1<<"---"<<incf[t]<<"--"<<d[t]<<endl;
    a[cnt].flow=incf[t];
    while(x!=s)
    {
        int i=pre[x];
        edge[i]-=incf[t];
        edge[i^1]+=incf[t];
        x=ver[i^1];
   //     printf("%d-->",x-1);
    }
  //  cout<<endl;
    maxflow+=incf[t];
}
bool check(LL x)
{
    LL sum=0;
    for (int i=1; i<=cnt; i++)
    {
        if (a[i].w<=x)
        {
            sum+=(LL)a[i].flow*(x-a[i].w+1);
        }
    }
    return sum>=k;
}
int main()
{
    int uu,vv,c;
    while(~scanf("%d%d%lld",&n,&m,&k))
    {
        cnt=0;
        tot=1;
        maxflow=0;
        s=1;
        t=n;
        memset(head,0,sizeof(head));
        for (int i=1; i<=m; i++)
        {
            scanf("%d%d%d",&uu,&vv,&c);
            add(uu+1,vv+1,c,1);
        }
        while(spfa())update();
        if (k==0)
        {
            printf("0\n");
        }
        else if (maxflow==0){
            printf("No solution\n");
        }else {
            int l=1,r=1e9;
            while(l<=r)
            {
                int mid=(l+r)>>1;
                if (check(mid))
                {
                    r=mid-1;
                    ans=mid;
                }
                else
                {
                    l=mid+1;
                }
            }
            printf("%lld\n",ans);
        }
    }
    return 0;
}

 

  

posted @ 2019-09-30 10:40  bluefly-hrbust  阅读(125)  评论(0编辑  收藏  举报