最小费用最大流问题,MCMF模板

发布时间 2023-08-03 20:22:25作者: CECY
// 最小费用最大流
struct MCMF
{
    struct node
    {
        int vi,id,wi,ci;
    };
    const int inf = 0x3f3f3f3f;
    int S,T,mxflow,cost;
    std::vector<int> dis,to,cur;
    std::vector<bool> vis;
    std::vector<std::vector<node>> r;
    MCMF(int n,int s,int t) : dis(n + 10),vis(n + 10),r(n + 10),cur(n + 10),S(s),T(t),mxflow(0),cost(0){}

    int spfa()//spfa代替bfs寻找增广路
    {
        std::fill(dis.begin(), dis.end(), inf);
        std::fill(vis.begin(), vis.end(), 0);
        queue<int> q;
        q.push(S);dis[S] = 0;
        while(q.size())
        {
            int x = q.front();q.pop();
            vis[x] = 0;//vis用于判断节点是否在队列中,若在,则最短路更新时不需重复加入队列
            for(auto tmp:r[x])
            {
                if(tmp.wi && dis[x] + tmp.ci < dis[tmp.vi])
                {
                    dis[tmp.vi] = dis[x] + tmp.ci;
                    if(!vis[tmp.vi])
                        q.push(tmp.vi),vis[tmp.vi] = 1;
                }
            }
        }
        if(dis[T] == inf)
            return 0;
        return 1;
    }

    int dfs(int x,int fl)
    {
        if(x == T)
            return fl;
        vis[x] = 1;//此处vis用于判断节点是否在目前选择的增广路上,若在,则不能重复加入。因为例题路径可能有0环存在
        int rem = fl;
        for(int i = 0;i < r[x].size();i ++)
        {
            if(rem == 0)
                break;
            int vi = r[x][i].vi,wi = r[x][i].wi,ci = r[x][i].ci;
            if(dis[x] + ci == dis[vi] && wi && !vis[vi])
            {
                int flow = dfs(vi,min(rem,wi));//找到可行流
                if(flow > 0)
                {
                    rem -= flow;
                    r[x][i].wi -= flow;
                    r[vi][r[x][i].id].wi += flow;
                    cost += ci*flow;//计算费用
                    if(rem <= 0)
                        break;
                }
                
            }
        }
        vis[x] = 0;//撤销点,看看能不能继续找到一条增广路
        if(fl == rem)
            dis[x] = inf;//如果从x点出发找不到可行流,则不再找x这个点
        return fl - rem;
    }

    void addEdge(int u,int v,int w,int c)//vector存图
    {
        r[u].push_back({v,(int)r[v].size(),w,c});
        r[v].push_back({u,(int)r[u].size() - 1,0,-c});
    }

    void Mxflow()//费用流
    {
        while(spfa())
        {
            for(auto &v:cur)
                v = 0;
            mxflow += dfs(S,inf);
        }
       //printf("%d %d\n",mxflow,cost);
    }

};