#102. 最小费用流

Problem A: #102. 最小费用流

Time Limit: 5 Sec   Memory Limit: 256 MB
Submit: 10   Solved: 5
[ Submit][ Status][ Web Board]

Description

这是一道模板题。

给定一个图,每条边有容量和费用,使用每条边的单位流量需要支付特定的费用。给定源点 1 和汇点n ,求图的最大流和最大流需要支付的最小费用。

Input

第一行两个整数 n m,表示有n 个点 m 条边。

从第二行开始的之后 m  行,每行四个整数siticiwi 表示一条从si 到 ti 的边,容量为ci,单位流量需要支付的费用为 wi

Output

一行两个整数,分别表示最大流和最大流需要支付的最小费用。

Sample Input

8 23
2 3 2147483647 1
1 3 1 1
2 4 2147483647 2
1 4 1 2
2 8 2 0
3 5 2147483647 3
1 5 1 3
3 6 2147483647 4
1 6 1 4
3 8 2 0
3 2 2147483647 0
4 6 2147483647 5
1 6 1 5
4 7 2147483647 6
1 7 1 6
4 8 2 0
4 2 2147483647 0
5 8 0 0
5 2 2147483647 0
6 8 0 0
6 2 2147483647 0
7 8 0 0
7 2 2147483647 0

Sample Output

6 24

HINT

1≤n≤400,0≤m≤15000 ,保证输入数据、中间结果以及答案在 32 位有符号整数范围内。


#include<cstdio>
#include<cstring>
const int maxn=1e4+10;
const int maxm=1e5+10;
const int maxt=2139062143;
inline int min_(int x,int y){return x<y?x:y;}
int n,m,s,t,nflow,nfee,flow,fee;
int a,b,c,d;
int h[maxn],hs=1;
int e_q[maxm],e_z[maxm],e_n[maxm],e_w[maxm],e_f[maxm];
int add(int q,int z,int k,int w,int f){e_q[k]=q,e_z[k]=z,e_n[k]=h[q],e_w[k]=w,e_f[k]=f,h[q]=k;}
int q[maxm],head,tail;
int w[maxn],p[maxn];
bool v[maxn];
int ap(int k,int v){
    if(k==s) return v;
    int ret=ap(e_q[p[k]],min_(v,e_w[p[k]]));
    if(!e_f[p[k]^1]) add(k,e_q[p[k]],p[k]^1,0,-e_f[p[k]]);
    e_w[p[k]]-=ret,e_w[p[k]^1]+=ret;
    return ret;
} 
void Mcmf(){
    while(1){
        memset(w,0x7f,sizeof(w));
        memset(v,0,sizeof(v));
        head=tail=w[s]=0;
        q[head++]=s,v[s]=1;
        while(head>tail){
            a=q[tail++],v[a]=0;
            for(int i=h[a];i;i=e_n[i])
            if(0ll+e_f[i]+w[a]<w[e_z[i]]&&e_w[i]){
                p[e_z[i]]=i;
                w[e_z[i]]=e_f[i]+w[a];
                if(!v[e_z[i]]) q[head++]=e_z[i],v[e_z[i]]=1;
            }
        }
        if(w[t]==maxt) break;
        nflow=ap(t,maxt);
        flow+=nflow;
        fee+=nflow*w[t];
    }
}
int main(){
    scanf("%d%d%d%d",&n,&m,&s,&t);
    for(int i=1;i<=m;i++){
        scanf("%d%d%d%d",&a,&b,&c,&d);
        ++hs,add(a,b,hs,c,d),hs++;
    }
    Mcmf();
    printf("%d %d\n",flow,fee);
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值