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

48 篇文章 0 订阅
23 篇文章 0 订阅

时间限制: 2 s
空间限制: 256000 KB
题目等级 : 大师 Master
题目描述 Description
有n件工作要分配给n个人做。第i 个人做第j 件工作产生的效益为ij c 。试设计一个将
n件工作分配给n个人做的分配方案,使产生的总效益最大。
«编程任务:
对于给定的n件工作和n个人,计算最优分配方案和最差分配方案。

输入描述 Input Description
第1 行有1 个正整数n,表示有n件工作要分配给n 个人做。接下来的n 行中,每行有n 个整数 cij ,1≤i≤n,1≤j≤n,表示第i 个人做第j件工作产生的效益为cij

输出描述 Output Description
将计算出的最小总效益和最大总效益输出

样例输入 Sample Input
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

样例输出 Sample Output
5
14

建图很简单,将人和任务分开就行,超级源点连人,流量为1,费用为0,人与任务之间流量为INF,费用为该人做此任务的价值,任务和超级汇点之间流量为1,费用为0,做一遍最小费用流,然后把所有费用变负,算最小费用;

#include<cstdio>
#include<climits>
#include<cstring>
#include<vector>
#include<queue>
#include<iostream>
using namespace std;
#define N 205
#define INF INT_MAX/3*2
struct NetWork{
    struct Edge{
        int fr,to,cap,flow,cost;
    };
    vector<Edge> edge;vector<int> g[N];
    int d[N*2],p[N*2],v[N][N],S,T;int n,m,cost;

    void clear(){
        for(int i=0;i<edge.size();i++)  edge[i].flow=0,edge[i].cost*=-1;
    }

    void Add_Edge(int fr,int to,int cap,int flow,int cost){
        edge.push_back(Edge{fr,to,cap,flow,cost});
        edge.push_back(Edge{to,fr,0,flow,-cost});
        m=edge.size();
        g[fr].push_back(m-2);g[to].push_back(m-1);
    }

    bool SPFA(){
        queue<int> q;bool b[N*2];
        for(int i=0;i<=T;i++) d[i]=INF;memset(b,0,sizeof(b));
        b[S]=true;q.push(S);d[S]=0;
        while(!q.empty()){
            int x=q.front();q.pop();b[x]=false;
            for(int i=0;i<g[x].size();i++){
                Edge &e=edge[g[x][i]];
                if(e.cap>e.flow&&d[e.to]>d[x]+e.cost){
                    d[e.to]=d[x]+e.cost;p[e.to]=g[x][i];
                    if(!b[e.to]){b[e.to]=true;q.push(e.to);}
                }               
            }
        }
        if(d[T]==INF) return false;
        cost+=d[T];
        for(int x=T;x!=S;x=edge[p[x]].fr){
            edge[p[x]].flow+=1;
            edge[p[x]^1].flow-=1;
        }
        return true;
    }

    void solve(){
        scanf("%d",&n);S=0,T=n*2+1,cost=0;int x;
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                scanf("%d",&x),Add_Edge(i,n+j,INF,0,x);
        for(int i=1;i<=n;i++)   Add_Edge(S,i,1,0,0),Add_Edge(n+i,T,1,0,0);
        while(SPFA());
        printf("%d\n",cost);
        cost=0;clear();
        while(SPFA());  
        printf("%d",-cost);
    }

}s;
int main(){
    s.solve();return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值