1.1.4.2 费用流之模板、直接应用、二分图最优匹配

1.1.4.2 费用流之模板、直接应用、二分图最优匹配

费用流模板

#include<bits/stdc++.h>
using namespace std;
const int MX_N=5010,MX_M=50100;
const int INF=0x3f3f3f3f;
struct node{
    int to,next;
    int w,cost;
}edge[MX_M<<1];
int head[MX_N]={0},edge_cnt=0;
inline void Add(int x,int y,int w,int c){
    node& it=edge[edge_cnt];
    it.cost=c;it.next=head[x];it.w=w;it.to=y;
    head[x]=edge_cnt++;
}

inline void add(int x,int y,int w,int c){
    Add(x,y,w,c),Add(y,x,0,-c);
}
int s=0,t=MX_N-1;
int pre[MX_N]={0},lim[MX_N]={0},dist[MX_N]={0};
bool vis[MX_N]={0};
bool spfa(){
    memset(lim,0,sizeof(lim));memset(dist,INF,sizeof(dist));memset(vis,0,sizeof(vis));
    queue<int >qu;
    qu.push(s);lim[s]=INF,vis[s]=1,dist[s]=0;
    while(!qu.empty()){
        int now=qu.front();qu.pop();vis[now]=0;
        for(int i=head[now];~i;i=edge[i].next){
            int to=edge[i].to,w=edge[i].w,cost=edge[i].cost;
            if(w&&dist[to]>dist[now]+cost){
                dist[to]=dist[now]+cost;
                pre[to]=i;
                lim[to]=min(lim[now],w);
                if(!vis[to]){
                    qu.push(to);
                    vis[to]=1;
                }
            }
        }
    }
    return lim[t]>0;
}
void EK(int &flow,int &cost){
    flow=cost=0;
    while(spfa()){
        flow+=lim[t];
        cost+=lim[t]*dist[t];
        for(int i=t;i!=s;i=edge[pre[i]^1].to){
            edge[pre[i]].w-=lim[t];
            edge[pre[i]^1].w+=lim[t];
        }
    }
}
signed main(){
    memset(head,-1,sizeof(head));
    //=======================================

    //=======================================
    return 0;
}

费用流直接应用

2192. 运输问题 P4015

\(S\) 向第 \(i\) 个仓库建容量为 \(a_i\) ,费用为 \(0\) 的边。

从第 \(j\) 个商店向 \(T\) 建容量为 \(b_i\),费用为 \(0\) 的边。

\(i\) 号仓库向 \(j\) 号商店连容量为 \(INF\) ,费用为 \(c_{i,j}\)的边。

先求最小费用最大流,再求最大费用最大流。

#include<bits/stdc++.h>
using namespace std;
const int MX_N=5010,MX_M=50100;
const int INF=0x3f3f3f3f;
struct node{
    int next,to;
    int w,c;
}edge[MX_M<<1];
int head[MX_N]={0},edge_cnt=0;
inline void Add(int x,int y,int w,int c){
    node &i=edge[edge_cnt];
    i.w=w,i.c=c,i.to=y,i.next=head[x];
    head[x]=edge_cnt++;
}
inline void add(int x,int y,int w,int c){
    Add(x,y,w,c);Add(y,x,0,-c);
}
int dist[MX_N]={0},lim[MX_N]={0},pre[MX_N]={0};
bool vis[MX_N]={0};
int s=0,t=MX_N-1;
bool spfa(){
    memset(dist,INF,sizeof(dist));
    memset(lim,0,sizeof(lim));
    memset(vis,0,sizeof(vis));
    queue<int >qu;
    qu.push(s);vis[s]=1,lim[s]=INF,dist[s]=0;
    while(!qu.empty()){
        int now=qu.front();qu.pop();vis[now]=0;
        for(int i=head[now];~i;i=edge[i].next){
            int to=edge[i].to,w=edge[i].w,c=edge[i].c;
            if(dist[to]>dist[now]+c&&w){
                dist[to]=dist[now]+c;
                lim[to]=min(lim[now],w);
                pre[to]=i;
                if(!vis[to]){
                    qu.push(to);
                    vis[to]=1;
                }
            }
        }
    }
    return lim[t]>0;
}

void EK(int &flow,int &cost){
    flow=cost=0;
    while(spfa()){
        flow+=lim[t];
        cost+=lim[t]*dist[t];
        for(int i=t;i!=s;i=edge[pre[i]^1].to){
            edge[pre[i]].w-=lim[t];
            edge[pre[i]^1].w+=lim[t];
        }
    }
}
signed main(){
    memset(head,-1,sizeof(head));
    //=======================================
    int m,n;scanf("%d%d",&m,&n);
    for(int i=1;i<=m;i++){
        int xi;scanf("%d",&xi);
        add(s,i,xi,0);
    }
    for(int i=1;i<=n;i++){
        int xi;scanf("%d",&xi);
        add(i+m,t,xi,0);
    }
    for(int i=1;i<=m;i++){
        for(int j=1;j<=n;j++){
            int xi;scanf("%d",&xi);
            add(i,j+m,INF,xi);
        }
    }
    int flow,cost;EK(flow,cost);
    printf("%d\n",cost);
    for(int i=0;i<edge_cnt;i++){
        edge[i].c=-edge[i].c;
    }
    for(int i=0;i<edge_cnt;i+=2){
        edge[i].w+=edge[i^1].w;
        edge[i^1].w=0;
    }
    EK(flow,cost);
    printf("%d",-cost);
    //=======================================
    return 0;
}
posted @ 2024-03-13 15:41  是菜菜呀  阅读(24)  评论(0编辑  收藏  举报