[网络流24题(5/24)] 分配问题(最小费用最大流)

Posted chen-jr

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[网络流24题(5/24)] 分配问题(最小费用最大流)相关的知识,希望对你有一定的参考价值。

传送门

分析:

非常经典的费用流的模型吧,也可以通过二分图最大匹配去做,但是鉴于二分图最大匹配的算法存在一定的局限性,故还是学一学较为通用的费用流的做法。

这道题目中本质上要讨论的问题跟运输问题,运输问题是一致的。

因为考虑到每个人只能被分配到一种货物,每种货物只能被一个人所分配,因此,我们不妨用流量将他们限流。

我们创建一个超级源地\\(sp\\),将\\(sp\\)跟每个人连一条流量为\\(1\\),费用为\\(0\\)的边。

同时我们创建一个超级汇点\\(ep\\),将每一种货物跟\\(ep\\)都连一条流量为\\(1\\),费用为\\(0\\)的边。

同时,对于每一个人和货物,我们对他们连一条流量为无穷的边。

因为每个人只能从超级源点获取最多\\(1\\)点的流量,每种货物只能向超级汇点传送最多\\(1\\)点的流量,因此当这个图满流时,能够保证每个人一定会配对最多一个货物,即达到我们限流的要求。

而如果我们需要求解最小花费,我们只需要将人和货物的边加上的费用取\\(val_ij\\),最后在这张图上跑最小费用最大流后最小费用即为答案。

而如果我们需要求解最大花费,我们只需要将人和货物的边加上的费用取相反数\\(-val_ij\\),最后在这张图上跑最小费用最大流后最小费用的相反数即为答案。

代码:

#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;

以上是关于[网络流24题(5/24)] 分配问题(最小费用最大流)的主要内容,如果未能解决你的问题,请参考以下文章

分配问题 网络流24题

网络流24题分配问题(二分图最佳匹配)(费用流)

「网络流24题」 18. 分配问题

网络流24题分配问题(费用流)

网络流24题餐巾计划问题(最小费用最大流)

网络流24题-题目总结