【网络流24题-18】分配问题 网络流 费用流

无人久伴 提交于 2020-03-30 06:49:40

题目描述

  有n件工作要分配给n(n<=100)个人做。第i个人做第 j件工作产生的效益为cij。试设计一个将n件工作分配给n个人做的分配方案,使产生的总效益最大。对于给定的n件工作和 n个人,计算最优分配方案和最差分配方案。

题目大意

  见题目描述A.A

数据范围

  见题目描述A.A

样例输入

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

解题思路

  S点向人连边,权值为1,费用为0,人向物品连边,权值为1,费用为Cij,物品向T连边,权值为1,费用为0。
  最小效益则为最小费用流,最大收益为最大费用流(关于最大费用流的问题,我是将费用取反,最后的答案也取反,当然也可以SPFA求最长路)。

代码

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <cmath>
#include <queue>
#define Maxn 23333
#define Maxe 23333
using namespace std;
inline int Getint(){int x=0,f=1;char ch=getchar();while('0'>ch||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while('0'<=ch&&ch<='9'){x=x*10+ch-'0';ch=getchar();}return x*f;}
int n,cnt=0,S,T,h1[Maxn],h2[Maxn],dis[Maxn],pre[Maxn],preto[Maxn],vis[Maxn];
struct node{int to,next,v,k,pair;}e1[Maxe],e2[Maxe];//e1,h1为求最小费用流,e2,h2为求最大费用流
void AddEdge(node *e,int h[],int x,int y,int v,int k,int pair){e[cnt]=(node){y,h[x],v,k,pair};h[x]=cnt;}
void AddEdge(node *e,int h[],int x,int y,int v,int k){AddEdge(e,h,x,y,v,k,++cnt+1);AddEdge(e,h,y,x,0,-k,++cnt-1);}
void Init(){
    n=Getint();
    S=0,T=n+n+1;
    int t;
    for(int i=1;i<=n;i++){
        AddEdge(e1,h1,S,i,1,0);
        AddEdge(e2,h2,S,i,1,0);
        for(int j=1;j<=n;j++)
            AddEdge(e1,h1,i,j+n,1,t=Getint()),AddEdge(e2,h2,i,j+n,1,-t);//建边,e2的费用取反
    }
    for(int j=1;j<=n;j++)
        AddEdge(e1,h1,j+n,T,1,0),AddEdge(e2,h2,j+n,T,1,0);
}
bool SPFA(node *e,int h[]){
    queue<int>Q;
    memset(dis,0x3f,sizeof(dis));
    memset(vis,0,sizeof(vis));
    memset(pre,0,sizeof(pre));
    dis[S]=0;
    vis[S]=1;
    Q.push(S);
    while(Q.size()){
        int x=Q.front();
        Q.pop();
        vis[x]=false;
        for(int p=h[x];p;p=e[p].next){
            int y=e[p].to;
            if(e[p].v&&dis[y]>dis[x]+e[p].k){
                pre[y]=p;
                preto[y]=x;
                dis[y]=dis[x]+e[p].k;
                if(!vis[y])Q.push(y);
            }
        }
    }
    return dis[T]<=(1<<29);
}
void Adjust(node *e,int &Ans){
    int flow=1<<30;
    for(int p=T;p!=S;p=preto[p])
        flow=min(flow,e[pre[p]].v);
    for(int p=T;p!=S;p=preto[p]){
        e[pre[p]].v-=flow;
        e[e[pre[p]].pair].v+=flow;
    }
    Ans+=dis[T]*flow;
}
int main(){
    int Ans1=0,Ans2=0;
    Init();
    while(SPFA(e1,h1))Adjust(e1,Ans1);
    cout<<Ans1<<"\n";
    while(SPFA(e2,h2))Adjust(e2,Ans2);
    cout<<-Ans2;//答案也取反
    return 0;
}
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!