最小费用最大流

#include<bits/stdc++.h>
using namespace std;
//假设无平行边和a-b b-a的回路,cost可以是负值
//利用bellmanford算法求最短路径,因为需要最小cost
//这个算法支持中途调用,但是调用时必须是最小cost状态,因为dp
const int maxn=1001;
int G[maxn][maxn],pre[maxn],n,m,flow[maxn][maxn],d[maxn],w[maxn][maxn],cost=0,as[maxn];//flow是当前的流量 a 代表到某个点的最小残余流量
//通过前驱数组求一条路径,当然结果可能会多了不是这条路径上的点的前驱,因为不一定能一次到
int flg[maxn];
int max_flow_with_cost(int s,int t){
    int f=0;
    memset(flow,0,sizeof(flow));
while(1){
    queue<int> q;
    q.push(s);
    memset(flg,0,sizeof(flg));
    memset(pre,0,sizeof(pre));
    memset(d,0x3f3f3f3f,sizeof(d));
    memset(as,0x3f3f3f3f,sizeof(as));
    flg[s]=1;
    d[s]=0;
    while(!q.empty()){
        int x=q.front();
        q.pop();
        flg[x]=0;//用于标识队列中如果有了,不重复加入队列
        for(int i=1;i<=n;i++){
            if(G[x][i]!=0&&G[x][i]>flow[x][i]&&d[x]+w[x][i]<d[i]){
                d[i]=d[x]+w[x][i];
                pre[i]=x;
                // as[i]=min(as[i],G[x][i]-flow[x][i]);
                if(!flg[i]){
                    flg[i]=1;
                    q.push(i);
                }
            }
        }
    }
    //t不可达即停止,当然也可以通过pre试试能不能到s然后停止,用a也可
    if(d[t]==0x3f3f3f3f) {cout<<"cost is "<<cost<<endl; return f;}
    int a=0x3f3f3f3f;
    // a=as[t];
    for(int i=t;pre[i]!=0;i=pre[i]) a=min(a,G[pre[i]][i]-flow[pre[i]][i]);
    for(int i=t;pre[i]!=0;i=pre[i]){
        flow[pre[i]][i]+=a;
        flow[i][pre[i]]-=a;
        cost+=a*w[pre[i]][i];
    }
    // cost+=a*d[t];
    f+=a;
}
}
int main() {
    cin>>n>>m;
    memset(G,0,sizeof(G));
    for(int i=0;i<m;i++){
        int x,y,z,k;
        cin>>x>>y>>z>>k;
        G[x][y]=z;
        w[x][y]=k;
    }
    cout<<max_flow_with_cost(1,2)<<endl;
    return 0;
}

 

posted @ 2020-06-06 21:51  西伯利亚挖土豆  阅读(155)  评论(0编辑  收藏  举报