2193. 分配问题(最小费用最大流解决最佳二分图问题)

有 n 件工作要分配给 n 个人做。

第 i 个人做第 j 件工作产生的效益为 cij。

试设计一个将 n 件工作分配给 n 个人做的分配方案。

对于给定的 n 件工作和 n 个人,计算最优分配方案和最差分配方案。

输入格式
第 1 行有 1 个正整数 n,表示有 n 件工作要分配给 n 个人做。

接下来的 n 行中,每行有 n 个整数 cij,表示第 i 个人做第 j 件工作产生的效益为 cij。

输出格式
第一行输出最差分配方案下的最小总效益。

第二行输出最优分配方案下的最大总效益。

数据范围
1≤n≤50,
0≤cij≤100
输入样例:

5
2 2 2 1 2
2 3 1 2 4
2 0 1 1 1
2 3 4 3 3
3 2 1 2 1
输出样例:
5
14
#include<bits/stdc++.h>
using namespace std;
const int N = 2 * 55;
const int M = (50 * 50 + 2 * 50) * 2;
const int INF = 0x3f3f3f3f;
struct Edge{
    int v,next,w,f;
}edge[M];
int head[N],cnt = 0;
void add(int u,int v,int f,int w){
    edge[cnt].v = v;
    edge[cnt].f = f;
    edge[cnt].w = w;
    edge[cnt].next = head[u];
    head[u] = cnt ++;
}
int n,m,s,e;
int g[N][N];
int d[N],q[N],hh = 0,tt = 0,pre[N],curf[N],st[N];
bool spfa(){        //最大流最大费用的话就求最长路即可
    memset(d,0x3f,sizeof d);
    memset(curf,0,sizeof curf);
    memset(st,0,sizeof st);
    hh = tt = 0;
    d[s] = 0,q[tt ++] = s,curf[s] = INF;
    st[s] = true;
    while(hh != tt){
        int t = q[hh ++];
        if(hh == N)hh = 0;
        st[t] = false;
        for(int i = head[t];~i;i = edge[i].next){
            int v = edge[i].v,w = edge[i].w;
            if(edge[i].f && d[v] > d[t] + w){
                d[v] = d[t] + w;
                pre[v] = i;
                curf[v] = min(edge[i].f,curf[t]);
                if(!st[v]){
                    q[tt ++] = v;
                    if(tt == N)tt = 0;
                    st[v] = true;
                }
            }
        }
    }
    return curf[e] > 0;
}
void EK(int &flow,int &cost){
    flow = cost = 0;
    while(spfa()){
        int t = curf[e];
        flow += t;cost += t * d[e];
        for(int i = e;i != s;i = edge[pre[i] ^ 1].v){
            edge[pre[i]].f -= t,edge[pre[i] ^ 1].f += t;
        }
    }
}
int main(){
    cin>>n;
    memset(head,-1,sizeof head);
    s = 0,e = 2 * n + 1;
    for(int i = 1;i <= n;i ++){
        for(int j = 1;j <= n;j ++){
            cin>>g[i][j];
        }
    }
    for(int i = 1;i <= n;i ++){
        add(s,i,1,0),add(i,s,0,0);
        add(i + n,e,1,0),add(e,i + n,0,0);
    }
    for(int i = 1;i <= n;i ++){
        for(int j = 1;j <= n;j ++){
            add(i,n + j,1,g[i][j]),add(j + n,i,0,-g[i][j]);
        }
    }
    int flow = 0,cost = 0;
    EK(flow,cost);
    cout<<cost<<endl;
    for(int i = 0;i < cnt;i += 2){      //求最坏匹配
        edge[i].f += edge[i ^ 1].f;
        edge[i ^ 1].f = 0;
        swap(edge[i].w,edge[i ^ 1].w);
    }
    EK(flow,cost);
    cout<<-cost<<endl;
    return 0;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值