最小费用最大流模板

来源:互联网 发布:平面设计师 美工招聘 编辑:程序博客网 时间:2024/05/29 18:32
/*最小费用最大流的模型在保证流量最大的前提下,所需的费用最小,这就是最小费用最大流问题.基本思路:    把弧<u,v>的单位费用c看作弧<u,v>的路径长度,每次找从源点s到汇点t长度最短(费用最小)的可增广路径进行增广。1. 最小费用可增广路2. 路径s到t的长度即[单位流量]的费用。ps:是网络流EK算法的改进,在求增广路径的时候,spfa每次求权值最小的增广路。ps:要注意一点,逆边cost[i][j] = -cost[j][i],不能忘了加上去。*///#include<bits/stdc++.h>#include <cstdio>#include <cstdlib>#include <iostream>#include <cstring>#include <string>#include <vector>#include <cmath>#include <map>#include <queue>#include <stack>#include <set>#include <algorithm>using namespace std;#define For(i,a,b) for(int (i)=(a);(i) < (b);(i)++)#define rof(i,a,b) for(int (i)=(a);(i) > (b);(i)--)#define IOS ios::sync_with_stdio(false)#define lson l,m,rt <<1#define rson m+1,r,rt<<1|1#define mem(a,b) memset(a,b,sizeof(a))typedef long long ll;typedef unsigned long long ull;void RI (int& x){    x = 0;    char c = getchar ();    while (c == ' '||c == '\n')    c = getchar ();    bool flag = 1;    if (c == '-'){        flag = 0;        c = getchar ();    }    while (c >= '0' && c <= '9'){        x = x * 10 + c - '0';        c = getchar ();    }    if (!flag)    x = -x;}void RII (int& x, int& y){RI (x), RI (y);}void RIII (int& x, int& y, int& z){RI (x), RI (y), RI (z);}/**************************************END define***************************************/const int maxn = 2e3+10;const int maxm = 2e4+10;const int INF =0x3f3f3f3f;struct Side{    int to,next,f,c;}side[maxm];//int flow;int cas, ans, top, n, m, s, t;int dis[maxn], pre[maxn], node[maxn];bool inqueue[maxn];queue<int> q;void add_side(int u,int v,int f,int c) //f是流量,c是单位流量的费用(当成路径长度){    side[top]=(Side){v,node[u],f,c};node[u]=top++;    side[top]=(Side){u,node[v],0,-c};node[v]=top++;}bool spfa(){    memset(inqueue,0,sizeof(inqueue));    memset(dis,0x3f,sizeof(dis));    q.push(s);    dis[s]=0;    //inqueue[s]=true;    pre[s]=-1;    while(!q.empty())//通过spfa得到最短路径(最小花费)的增广路    {        int u=q.front();        q.pop();        inqueue[u]=0;        for(int i=node[u];i!=-1;i=side[i].next)        {           int v=side[i].to;            if(dis[v]>dis[u]+side[i].c&&side[i].f>0)            {                //cout<<u<<" "<<v<<" ";                dis[v]=dis[u]+side[i].c;                pre[v]=i; //连接点v的前一条边                if(!inqueue[v])                {                    inqueue[v]=true;                    q.push(v);                }            }        }    }    if (dis[t] == INF) return false; // 无增广路,结束    int aug=INF;     for(int p=pre[t];p!=-1;p=pre[side[p^1].to])        aug=min(aug,side[p].f); //本条增广路的流量    for(int p=pre[t];p!=-1;p=pre[side[p^1].to])    {        side[p].f -= aug;   //路径中的边流量减掉aug        side[p^1].f += aug;  //反向边+aug    }    //flow+=aug;    //最小费用最大流的流量和    ans += dis[t] * aug;    //单位流量的花费*流量    return true;}int main(){    //freopen("in.txt","r",stdin);    scanf("%d",&cas);    while(cas--)    {    //flow=0;    top=0;    scanf("%d%d%d%d", &n, &m, &s, &t);//这里给源点汇点赋值    memset(node,-1,sizeof(node));    for(int i=0;i<m;i++)    {        int u,v,f,c;        scanf("%d%d%d%d", &u, &v, &f, &c);        add_side(u,v,f,c);    }    ans=0;    while(spfa());    printf("%d\n",ans); //ans返回的是最小费用最大流的   权值和    //printf("flow=%d\n",flow );  //返回的是最小费用最大流的   总流量    }    return 0;}
http://paste.ubuntu.com/12197696/


0 0
原创粉丝点击