题意:给定N个垃圾桶,每个垃圾桶内装有N种数量不同的垃圾,现把垃圾分类,每个垃圾桶装一种垃圾,移动一个单位的垃圾消耗代价,求最小代价。
思路:最佳二分匹配,KM算法处理,注意最小,将边权置负。
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include <iostream>
using namespace std;
#define MAX 302
int N;
const int inf=10000000;
bool x[MAX],y[MAX];
int map[MAX][MAX];
int my[MAX];
int lx[MAX],ly[MAX];
int slack[MAX];
bool dfs(int t){
int u;
x[t]=1;
for(u=1;u<=N;u++){
int wt=lx[t]+ly[u]-map[t][u];
if(!y[u]&&wt==0){
y[u]=1;
if(my[u]==-1||dfs(my[u])){
my[u]=t;
return 1;
}
}
else if(slack[u]>wt) slack[u]=wt;
}
return 0;
}
int perfect_match(){
int i,j,k;
for(i=1;i<=N;i++){
my[i]=-1;
lx[i]=-inf,ly[i]=0;
for(j=1;j<=N;j++){
if(lx[i]<map[i][j]) lx[i]=map[i][j];
}
}
for(k=1;k<=N;k++){
memset(x,0,sizeof(x));
memset(y,0,sizeof(y));
for(i=1;i<=N;i++) slack[i]=inf;
while(!dfs(k)){
int d=inf;
for(i=1;i<=N;i++){
if(!y[i]&&slack[i]<d){d=slack[i];}
}
for(i=1;i<=N;i++){
if(x[i]){
lx[i]=lx[i]-d;
x[i]=0;
}
if(y[i]){
ly[i]=ly[i]+d;
y[i]=0;
}
}
}
}
int ans=0;
for(i=1;i<=N;i++)
ans+=(lx[i]+ly[i]);
return ans;
}
int main(){
int cost;
scanf("%d",&N);
for(int i=1;i<=N;i++){
cost=0;
for(int j=1;j<=N;j++){
scanf("%d",&map[i][j]);
cost+=map[i][j];
}
for(int j=1;j<=N;j++)
map[i][j]=cost-map[i][j];
}
for(int i=1;i<=N;i++)
for(int j=1;j<=N;j++)
map[i][j]=-map[i][j];
cout<<-perfect_match()<<endl;
return 0;
}
/*测试:
Sample Input
4
62 41 86 94
73 58 11 12
69 93 89 88
81 40 69 13
Sample Output
650
*/