codevs 1422 河城荷取

时间限制: 1 s
 空间限制: 128000 KB
 题目等级 : 大师 Master
题目描述 Description

在幻想乡,河城荷取是擅长高科技工业的河童。荷取的得意之作除了光学迷彩外,还有震动整个幻想乡的巨型人形『非想天则』。不过由于人形太过巨大,所以为它充能是一件很麻烦的事。人形一共有N个电能池,编号1..N。其中前L个电能池(即编号为1..L的电能池)连接着外部充能接口,而编号为N的电能池连接着动力炉核心。在N个蓄能池之间有M条单向管道,每条管道有一个激活代价cost和电能传输极限limit。当激活度达到某个值时,所以激活代价小于等于这个值的管道都会被激活,但是每一条管道只能够最多传送limit个单位的电能。外部接口到电能池和电能池到动力炉核心的管道传输没有限制并且激活代价为0。现在荷取想往动力炉核心输入至少K个单位的电能,求需要的最小激活度。

输入描述 Input Description

第1行:4个正整数N,M,L, K
  第2..M行:4个整数,u,v,limit,cost,表示一条由u到v的管道,传输极限limit,激活代价为cost

输出描述 Output Description

第1行:1个整数,表示最小激活代价

样例输入 Sample Input

6 5 3 3
1 4 2 4
2 4 3 5
3 5 4 2
4 6 2 3
5 6 3 4

样例输出 Sample Output

4

数据范围及提示 Data Size & Hint

数据范围
  对于30%的数据:1 ≤ L ≤ N ≤ 100,0 ≤ M ≤ 2,000,1 ≤ cost ≤ 10,000
  对于60%的数据:1 ≤ L ≤ N ≤ 1,000,0 ≤ M ≤ 20,000,1 ≤ cost ≤ 10,000
  对于100%的数据:1 ≤ L ≤ N ≤ 2,000,0 ≤ M ≤ 80,000,1 ≤ cost ≤ 1,000,000
  对于100%的数据:1 ≤ limit ≤ 1,000
 提示
  样例解释:
  当激活度为4时,除了(2,4)外其他管道都能够使用。此时能够输入恰好4个单位电能。具体如下:
  (1,4) 输送2个单位电力
  (4,6) 输送2个单位电力
  (3,5) 输送2个单位电力
  (5,6) 输送2个单位电力
  

  注意:
  保证任意(u,v)都只出现一次。

 
二分代价+网络流dinic验证。
#include <cstring>
#include <cstdio>
#include <queue>
#define INF 0x7ffffff
#define M 80005
#define N 2005

using namespace std;
void read(int &x)
{
    x=0;bool f=0;
    char ch=getchar();
    for(;ch>'9'||ch<'0';ch=getchar()) if(ch=='-') f=1;
    for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
    x=f?(~x)+1:x;
}
struct Edge
{
    int next,to,flow;
    Edge (int next=0,int to=0,int flow=0) :next(next),to(to),flow(flow){}
}edge[M<<1];
int S,T,u[M],v[M],lim[M],cost[M],n,m,l,k,dep[N],head[N<<1],cnt=1;
void insert(int u,int v,int w)
{
    edge[++cnt]=Edge(head[u],v,w);
    head[u]=cnt;
}
void build(int x)
{
    memset(head,0,sizeof(head));
    memset(edge,0,sizeof(edge));
    cnt=1;
    for(int i=1;i<=m;i++)
    {
        if(cost[i]<=x)
        {
            insert(u[i],v[i],lim[i]);
            insert(v[i],u[i],0);
        }
    }
    for(int i=1;i<=l;i++)
    {
        insert(S,i,INF);
        insert(i,S,0);
    }
}
bool bfs()
{
    memset(dep,-1,sizeof(dep));
    queue<int>q;
    q.push(S);
    dep[S]=0;
    while(!q.empty())
    {
        int Top=q.front();
        q.pop();
        for(int i=head[Top];i;i=edge[i].next)
        {
            int v=edge[i].to;
            if(dep[v]==-1&&edge[i].flow)
            {
                dep[v]=dep[Top]+1;
                q.push(v);
            }
        }
    }
    if(dep[T]>0) return true;
    else return false;
}
int dfs(int now,int t,int came_flow)
{
    int f,rest=0;
    if(now==t||came_flow==0) return came_flow;
    for(int i=head[now];i;i=edge[i].next)
    {
        int v=edge[i].to;
        if(dep[v]==dep[now]+1&&edge[i].flow&&(f=dfs(v,t,min(came_flow,edge[i].flow))))
        {
            rest+=f;
            came_flow-=f;
            edge[i].flow-=f;
            edge[i^1].flow+=f;
            if(came_flow==0) return rest;
        }
    }
    if(rest==0) dep[now]=INF;
    return rest;
}
int dinic()
{
    int ans=0;
    for(;bfs();ans+=dfs(S,T,INF));
    return ans;
}
int main()
{
    read(n);
    read(m);
    read(l);
    read(k);
    S=n+1,T=n;
    for(int i=1;i<=m;i++)
    {
        read(u[i]);
        read(v[i]);
        read(lim[i]);
        read(cost[i]);
    }
    int l=-1,r=1000000;
    while(r-l>1)
    {
        int mid=(l+r)>>1;
        build(mid);
        if(dinic()>=k)
            r=mid;
        else l=mid;
    }
    printf("%d",r);
    return 0;
}
我们都在命运之湖上荡舟划桨,波浪起伏着而我们无法逃脱孤航。但是假使我们迷失了方向,波浪将指引我们穿越另一天的曙光。
原文地址:https://www.cnblogs.com/ruojisun/p/7209155.html