题目描述

nnn 件工作要分配给 nnn 个人做。第 iii 个人做第 jjj 件工作产生的效益为 cijc_{ij}cij 。试设计一个将 nnn 件工作分配给 nnn 个人做的分配方案,使产生的总效益最大。

输入格式

文件的第 111 行有 111 个正整数 nnn,表示有 nnn 件工作要分配给 nnn 个人做。

接下来的 nnn 行中,每行有 nnn 个整数 cijc_{ij}cij​​,表示第 iii 个人做第 jjj 件工作产生的效益为 cijc_{ij}cij

输出格式

两行分别输出最小总效益和最大总效益。

输入输出样例

输入 #1
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
输出 #1
5
14

说明/提示

1≤n≤1001 \leq n \leq 1001n100

一个人只能修一个工件

思路

人和任务可以划分为二分图,建图+最大流最小费用和最大流最大费用

代码

#include<bits/stdc++.h>
#define N 10007
#define M 200007
#define inf 1<<29
using namespace std;
struct node{
    int y,z,next,p;
}e[M*2];
int a[107][107],head[N*4];
int n,s,t,tot=1,maxflow,ans;
void add(int x,int y,int z,int p){
    e[++tot].y=y;e[tot].z=z;e[tot].p=p;e[tot].next=head[x];head[x]=tot;
    e[++tot].y=x;e[tot].z=0;e[tot].p=-p;e[tot].next=head[y];head[y]=tot;
}
int incf[N],v[N],pre[N],d[N];
bool spfa(){
    queue<int> q;
    memset(d,0x3f,sizeof(d));
    memset(v,0,sizeof(v));
    q.push(s);d[s]=0;v[s]=1;
    incf[s]=inf;
    while(!q.empty()){
        int x=q.front();v[x]=0;q.pop();
        for(int i=head[x];i;i=e[i].next){
            int y=e[i].y,z=e[i].z;
            if(!z) continue;
            if(d[y]>d[x]+e[i].p){
                d[y]=d[x]+e[i].p;
                incf[y]=min(incf[x],z);
                pre[y]=i;
                if(!v[y]) q.push(y),v[y]=1;
            }
        }
    }
    if(d[t]==0x3f3f3f3f) return false;
    return true;
}
void update(){
    int x=t;
    while(x!=s){
        int i=pre[x];
        e[i].z-=incf[t];
        e[i^1].z+=incf[t];
        x=e[i^1].y;
    }
    ans+=d[t]*incf[t];
}
int main()
{
    cin>>n;s=0;t=n*2+1;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            cin>>a[i][j];
    for(int i=1;i<=n;i++)
        add(s,i,1,0),add(i+n,t,1,0);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            add(i,j+n,1,a[i][j]);
    while(spfa()) update();
    cout<<ans<<endl;
    memset(head,0,sizeof(head));tot=1;maxflow=ans=0;
    for(int i=1;i<=n;i++)
        add(s,i,1,0),add(i+n,t,1,0);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            add(i,j+n,1,-a[i][j]);
    while(spfa()) update();
        cout<<-ans<<endl;
    return 0;
}
02-12 20:06