P4014 分配问题

题目描述

\(n\) 件工作要分配给 \(n\) 个人做。第 \(i\) 个人做第 \(j\) 件工作产生的效益为 \(c_{ij}\) 。试设计一个将 \(n\) 件工作分配给 \(n\) 个人做的分配方案,使产生的总效益最大。

输入输出格式

输入格式

文件的第 \(1\) 行有 \(1\) 个正整数 \(n\),表示有 \(n\) 件工作要分配给 \(n\) 个人做。

输出格式

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

输入输出样例

输入样例 #1

5
2 2 2 1 2
2 3 1 2 4
2 0 1 1 1
2 3 4 3 3

输出样例 #1

5 14

显然是KM算法(下文是优化),先要将负的权值传进去,输出,再初始化,再传正的权值进去,再输出

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
using namespace std;
typedef long long ll;
const ll Maxn=505;
const ll inf=1e18;
ll n,m,map[Maxn][Maxn],matched[Maxn];
ll slack[Maxn],pre[Maxn],ex[Maxn],ey[Maxn];
ll a[105][105];
bool visx[Maxn],visy[Maxn];
void match(ll u)
{	
    ll x,y=0,yy=0,delta;
    memset(pre,0,sizeof(pre));
    for(ll i=1;i<=n;i++)slack[i]=inf;
    matched[y]=u;
    while(1)
    {	
        x=matched[y];delta=inf;visy[y]=1;
        for(ll i=1;i<=n;i++)
        {	
            if(visy[i])continue;
            if(slack[i]>ex[x]+ey[i]-map[x][i])
            {	
                slack[i]=ex[x]+ey[i]-map[x][i];
                pre[i]=y;
            }
            if(slack[i]<delta){delta=slack[i];yy=i;}
        }
        for(ll i=0;i<=n;i++)
        {	
            if(visy[i])ex[matched[i]]-=delta,ey[i]+=delta;
            else slack[i]-=delta;
        }
        y=yy;
        if(matched[y]==-1)break;
    }
    while(y){matched[y]=matched[pre[y]];y=pre[y];}
}
ll KM()
{	
    memset(matched,-1,sizeof(matched));
    memset(ex,0,sizeof(ex));
    memset(ey,0,sizeof(ey));
    for(ll i=1;i<=n;i++)
    {	
        memset(visy,0,sizeof(visy));
        match(i);
    }
    ll res=0;
    for(ll i=1;i<=n;i++)
        if(matched[i]!=-1)res+=map[matched[i]][i];
    return res;
}
int main()
{	
	ll w;
    scanf("%lld",&n);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            map[i][j]=-inf;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++){
        	scanf("%lld",&map[i][j]);
		}
    
    for(ll i=1;i<=n;i++)
    	for (ll j=1;j<=n;j++)
    	    map[i][j]=-1*map[i][j];
	printf("%lld\n",-1*KM());
	for(ll i=1;i<=n;i++)
    	for (ll j=1;j<=n;j++)
    	    map[i][j]=-1*map[i][j];
    printf("%lld\n",KM());
    return 0;
}
posted @ 2021-08-26 17:33  hewt  阅读(47)  评论(0编辑  收藏  举报