[網絡流24題(5/24)] 分配問題(最小費用最大流)

傳送門html

分析:

很是經典的費用流的模型吧,也能夠經過二分圖最大匹配去作,可是鑑於二分圖最大匹配的算法存在必定的侷限性,故仍是學一學較爲通用的費用流的作法。c++

這道題目中本質上要討論的問題跟運輸問題,運輸問題是一致的。算法

由於考慮到每一個人只能被分配到一種貨物,每種貨物只能被一我的所分配,所以,咱們不妨用流量將他們限流。spa

咱們建立一個超級源地\(sp\),將\(sp\)跟每一個人連一條流量爲\(1\),費用爲\(0\)的邊。code

同時咱們建立一個超級匯點\(ep\),將每一種貨物跟\(ep\)都連一條流量爲\(1\),費用爲\(0\)的邊。htm

同時,對於每個人和貨物,咱們對他們連一條流量爲無窮的邊。blog

由於每一個人只能從超級源點獲取最多\(1\)點的流量,每種貨物只能向超級匯點傳送最多\(1\)點的流量,所以當這個圖滿流時,可以保證每一個人必定會配對最多一個貨物,即達到咱們限流的要求。get

而若是咱們須要求解最小花費,咱們只須要將人和貨物的邊加上的費用取\(val_{ij}\),最後在這張圖上跑最小費用最大流後最小費用即爲答案。it

而若是咱們須要求解最大花費,咱們只須要將人和貨物的邊加上的費用取相反數\(-val_{ij}\),最後在這張圖上跑最小費用最大流後最小費用的相反數即爲答案。class

代碼:

#include <bits/stdc++.h>
#define maxn 4050
using namespace std;
struct Node{
    int to,next,val,cost;
}q[maxn<<1];
int head[maxn],cnt=0;
int dis[maxn],vis[maxn],sp,ep,maxflow,cost;
int n,num[maxn][maxn];
const int INF=0x3f3f3f3f;
void init(){
    memset(head,-1,sizeof(head));
    cnt=2;
    maxflow=cost=0;
}
void addedge(int from,int to,int val,int cost){
    q[cnt].to=to;
    q[cnt].next=head[from];
    q[cnt].val=val;
    q[cnt].cost=cost;
    head[from]=cnt++;
}
void add_edge(int from,int to,int val,int cost){
    addedge(from,to,val,cost);
    addedge(to,from,0,-cost);
}
bool spfa(){
    memset(vis,0,sizeof(vis));
    memset(dis,0x3f,sizeof(dis));
    dis[sp]=0;
    vis[sp]=1;
    queue<int>que;
    que.push(sp);
    while(!que.empty()){
        int x=que.front();
        que.pop();
        vis[x]=0;
        for(int i=head[x];i!=-1;i=q[i].next){
            int to=q[i].to;
            if(dis[to]>dis[x]+q[i].cost&&q[i].val){
                dis[to]=dis[x]+q[i].cost;
                if(!vis[to]){
                    que.push(to);
                    vis[to]=1;
                }
            }
        }
    }
    return dis[ep]!=0x3f3f3f3f;
}
int dfs(int x,int flow){
    if(x==ep){
        vis[ep]=1;
        maxflow+=flow;
        return flow;
    }//能夠到達t,加流
    int used=0;//該條路徑可用流量
    vis[x]=1;
    for(int i=head[x];i!=-1;i=q[i].next){
        int to=q[i].to;
        if((vis[to]==0||to==ep)&&q[i].val!=0&&dis[to]==dis[x]+q[i].cost){
            int minflow=dfs(to,min(flow-used,q[i].val));
            if(minflow!=0){
                cost+=q[i].cost*minflow;
                q[i].val-=minflow;
                q[i^1].val+=minflow;
                used+=minflow;
            }
            //能夠到達t,加費用,扣流量
            if(used==flow)break;
        }
    }
    return used;
}int mincostmaxflow(){
    while(spfa()){
        vis[ep]=1;
        while(vis[ep]){
            memset(vis,0,sizeof(vis));
            dfs(sp,INF);
        }
    }
    return maxflow;
}
int main()
{
    scanf("%d",&n);
    init();
    sp=2*n+1,ep=2*n+2;

    for(int i=1;i<=n;i++){
        add_edge(sp,i,1,0);
        add_edge(i+n,ep,1,0);
    }
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            scanf("%d",&num[i][j]);
            add_edge(i,j+n,INF,num[i][j]);
        }
    }
    mincostmaxflow();
    printf("%d\n",cost);

    init();
    for(int i=1;i<=n;i++){
        add_edge(sp,i,1,0);
        add_edge(i+n,ep,1,0);
    }
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            add_edge(i,j+n,INF,-num[i][j]);
        }
    }
    mincostmaxflow();
    printf("%d\n",-cost);
    return 0;
}
相關文章
相關標籤/搜索