【codevs1422】河城荷取 二分+dinic

题目描述 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写傻了

然后过了两天再来写,一遍A了…………

总之就是不要忘记清空数组!!!别的都好说

代码:

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;

const int SZ=1000010;
const int INF=1000000000;

int head[SZ],nxt[SZ],tot=1,s,e;

struct edge{
    int t,d;
}l[SZ];

void build(int f,int t,int d)
{
    l[++tot].t=t;
    l[tot].d=d;
    nxt[tot]=head[f];
    head[f]=tot;
}

int deep[SZ];
queue<int> q;
bool bfs(int s)
{
    q.push(s);
    deep[s]=1;
    while(q.size())
    {
        int f=q.front(); q.pop();
        for(int i=head[f];i;i=nxt[i])
        {
            int v=l[i].t;
            if(l[i].d && !deep[v])
            {
                deep[v]=deep[f]+1;
                q.push(v);
            }
        }
    }
    if(deep[e]) return true;
    return false;
}

int dfs(int u,int flow)
{
    if(u==e || flow==0) return flow;
    int ans=0;
    for(int i=head[u];i;i=nxt[i])
    {
        int v=l[i].t;
        if(l[i].d && deep[v]==deep[u]+1)
        {
            int f=dfs(v,min(flow,l[i].d));
            if(f > 0)
            {
                l[i].d-=f;
                l[i^1].d+=f;
                flow-=f;
                ans+=f;
                if(flow==0) return ans;
            }
        }
    }
    if(ans == 0) deep[u]=INF;
    return ans;
}

int dinic()
{
    int ans=0;
    while(bfs(s))
    {
        int tmp=dfs(s,INF);
        if(tmp==0) break;
        ans+=tmp;
        memset(deep,0,sizeof(deep));
    }
    return ans;
} 

int ff[SZ],tt[SZ],ll[SZ],dd[SZ];
int n,m,L,k;

void init()
{
    memset(head,0,sizeof(head));
    memset(nxt,0,sizeof(nxt));
    memset(l,0,sizeof(l));
    memset(deep,0,sizeof(deep));
    tot=1;
}

void build_graph(int ans)
{
    init();
    for(int i=1;i<=m;i++)
    {
        if(dd[i]<=ans)
        {   
            build(ff[i],tt[i],ll[i]);
            build(tt[i],ff[i],0);
        }
    }
    for(int i=1;i<=L;i++)
    {
        build(s,i,INF); build(i,s,0);
    }
}



int div()
{
    int s=-1,t=1000000;
    while(t-s>1)
    {
        int mid=(t+s)>>1;
        build_graph(mid);
        if(dinic()>=k) t=mid;
        else s=mid;
    }
    return t;
}


int main()
{
    scanf("%d%d%d%d",&n,&m,&L,&k);
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d%d%d",&ff[i],&tt[i],&ll[i],&dd[i]);
    }
    s=n+1,e=n;  
    printf("%d",div());
    return 0;

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值