最小費用最大流(板子)

最小費用最大流

步驟:
1.spfa()找最小費用的路徑,並記錄;
2.利用最大流維護路徑;
模板題:洛谷P3381

#include <bits/stdc++.h>
using namespace std;
const int N=5020;
const int maxn=1e5+55;
const int inf=0x3f3f3f3f;
int dis[N],head[maxn],pre[N],f[N]; //dis[]記錄最小花費,pre[]記錄節點值,f[]記錄路徑最小流量;
int cnt=0,s,t,max_flow=0,min_cost=0;
struct node{             //鏈式向前星建邊;
    int u,to,next,cost,flow;
}mp[maxn];
inline void add(int x, int y, int cost,int val)
{
    mp[cnt].u=x;
    mp[cnt].to=y;
    mp[cnt].cost=cost;
    mp[cnt].flow=val;
    mp[cnt].next=head[x];
    head[x]=cnt++;
}
int spfa() //跑spfa,找到滿足條件的最小化費;
{
    bool p[N];
    for(int i=0;i<N;++i)
    {
        p[i]=false;
        dis[i]=inf;
        pre[i]=-1;
    }
    queue<int >q;
    q.push(s);
    dis[s]=0;
    f[s]=inf;
    while(!q.empty()){
        int u=q.front();
        q.pop();
        p[u]=false;
        for(int i=head[u];~i;i=mp[i].next){
            int to=mp[i].to;
            int cost=mp[i].cost;
            int flow=mp[i].flow;
            if(flow>0&&dis[to]>dis[u]+cost){
                dis[to]=dis[u]+cost;
                f[to]=min(f[u],flow);     //找路徑最小流量;
                pre[to]=i;            //記錄節點的值,用於後面的維護路徑流量;
                if(!p[to]){
                    p[to]=true;
                    q.push(to);
                }
            }
        }
    }
    return pre[t];
}
void EK()
{
    while(spfa()!=-1){
        int now=t,las=pre[now];
        while(s^now){            //回溯路徑,維護流量;
            mp[las].flow-=f[t];
            mp[las^1].flow+=f[t];
            now=mp[las].u;
            las=pre[now];
        }
        min_cost+=f[t]*dis[t];
        max_flow+=f[t];
    }
}
int main()
{
    int n,m,x,y,cost,val;
    memset(head,-1,sizeof(head));
    scanf("%d%d%d%d",&n,&m,&s,&t);
    for(int i=0;i<m;++i){
        scanf("%d%d%d%d",&x,&y,&val,&cost);
        add(x,y,cost,val);             //建邊;
        add(y,x,-cost,0);
    }
    EK();
    printf("%d %d\n",max_flow,min_cost);
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章