luoguP3381 【模板】最小费用最大流

题目描述

如题,给出一个网络图,以及其源点和汇点,每条边已知其最大流量和单位流量费用,求出其网络最大流和在最大流情况下的最小费用。

输入输出格式

输入格式:
第一行包含四个正整数N、M、S、T,分别表示点的个数、有向边的个数、源点序号、汇点序号。
接下来M行每行包含四个正整数ui、vi、wi、fi,表示第i条有向边从ui出发,到达vi,边权为wi(即该边最大流量为wi),单位流量的费用为fi。

输出格式:
一行,包含两个整数,依次为最大流量和在最大流量情况下的最小费用。

输入输出样例

输入样例#1:
4 5 4 3
4 2 30 2
4 3 20 3
2 3 20 1
2 1 30 9
1 3 40 5

输出样例#1:
50 280

说明
时空限制:1000ms,128M

数据规模:
对于30%的数据:N<=10,M<=10
对于70%的数据:N<=1000,M<=1000
对于100%的数据:N<=5000,M<=50000

分析:模板题
注意两点:1.判断时不能使用0x7f,原因是不能精准判断,只能大致估计,所以在memeset时最好使用0x33,这样在判断时的写法为dis[t]<0x33333333(8个3)
2.记得加快读

这里写代码片
#include<cstdio>
#include<cstring>
#include<iostream>
#include<queue>

using namespace std;

const int INF=0x33333333;
const int N=1001000;
struct node{
    int x,y,v,cost,next;
};
node way[N*2];
int st[N],tot=-1;
int n,m,s,t,flow=0,ans=0; 
bool p[N];
int pre[N],dis[N];  ///

int in()  //快读
{
    int t=0;
    char ch=getchar();
    while(ch>'9'||ch<'0') ch=getchar();
    while(ch>='0'&&ch<='9') t=(t<<1)+(t<<3)+ch-'0',ch=getchar();
    return t;
}

void add(int u,int w,int z,int c)
{
    tot++;
    way[tot].x=u;way[tot].y=w;way[tot].v=z;way[tot].cost=c;way[tot].next=st[u];st[u]=tot;
    tot++;
    way[tot].x=w;way[tot].y=u;way[tot].v=0;way[tot].cost=-c;way[tot].next=st[w];st[w]=tot;
}

int spfa()
{
    int i;
    memset(pre,0,sizeof(pre));
    memset(p,1,sizeof(p));
    memset(dis,0x33,sizeof(dis));  //花费   ////0x33
    queue<int> q;
    q.push(s);
    dis[s]=0;
    p[s]=0;
    while (!q.empty())
    {
        int r=q.front();
        q.pop();
        for (i=st[r];i!=-1;i=way[i].next)
        {
            if (way[i].v&&dis[way[i].y]>dis[r]+way[i].cost)  //
            {
                dis[way[i].y]=dis[r]+way[i].cost;
                pre[way[i].y]=i;  //记录一下修改来自哪条路
                if (p[way[i].y])
                {
                    p[way[i].y]=0;
                    q.push(way[i].y);    
                } 
            }
        }
        p[r]=1;  ///
    }
    return dis[t]<INF;
}

void doit()
{
    int sum,i;
    while (spfa())
    {
        sum=INF;  //增广量
        for (i=t;i!=s;i=way[pre[i]].x)  //从汇点反向增广
            sum=min(sum,way[pre[i]].v);  //流量 
        ans+=dis[t]*sum;
        flow+=sum;
        for (i=t;i!=s;i=way[pre[i]].x)
        {
            way[pre[i]].v-=sum;
            way[pre[i]^1].v+=sum;
        } 
    }
    printf("%d %d
",flow,ans);
    return;
}

int main()
{
    memset(st,-1,sizeof(st));
    n=in();m=in();s=in();t=in();
    for (int i=1;i<=m;i++)
    {
        int u,w,z,c;
        u=in();w=in();z=in();c=in();
        add(u,w,z,c);
    }
    doit();
    return 0;
} 
原文地址:https://www.cnblogs.com/wutongtong3117/p/7673633.html