最佳匹配是我们经常会遇到的问题,我们通常使用匈牙利算法或KM算法解决这类问题。这类问题离不开权值的比较,也就是我们最爱举的例子——男女最佳匹配中的某个男孩更爱某个女孩的具体数值了。这里我找了个大神的讲解,非常通俗易懂,具体如下。
点击这里
我们可以这么理解,第一次,男生都向最喜欢的告白,女生当然只能接受数值最高那个啦,但这只是暂时的。第二次男生吸取教训,被拒绝的男生把拒接他的女生的名字从名单中去掉,向第二喜欢的告白,同第一次一样,女生继续拒绝。同样是暂时的。当所有人都有匹配对象时,匹配结束,这是即使最佳匹配。
(ps:估计也大三大四了吧。。。)
好,了解了以后,我们来做一道题。
例题
代码如下
import java.util.Scanner;
public class trash {
static int max =1000;
static int inf =0x3f3f3f3f;
static int n;//垃圾桶数量 垃圾种类
static int ans;
static int en;
static int st;
static int cap[][]=new int[max][max];//是否有关系 关系路径
static int pre[]=new int[max];//确认关系 关系路径(最终)
static int cost[][]=new int[max][max],//除了第j种垃圾 第i个垃圾箱有多少垃圾(最终)
dis[]=new int[max];
static int que[]=new int[max];//连线
static boolean vis[]=new boolean[max];
static int r[][]=new int[max][max],
s[]=new int[max];
static boolean spfa(){
int i, head = 0, tail = 1;
for(i = 1; i <= n; i ++){//n=2n+2
dis[i] = inf;
vis[i] = false;
}
dis[st] = 0;//st=2n+1
que[0] = st;
vis[st] = true;
while(tail != head){ // 循环队列。
int u = que[head];//既2n+1
for(i = 1; i <= n; i ++)
if(cap[u][i]==1 && dis[i] > dis[u] + cost[u][i]){ // 存在路径
dis[i] = dis[u] + cost[u][i];//除了第i种垃圾 第u个垃圾箱有多少垃圾
// System.out.println(dis[i]);
pre[i] = u;
if(!vis[i]){
vis[i] = true;//已占用 更合适
que[tail] = i;
//System.out.println(dis[i]+" "+tail+" "+i);
tail ++;
if(tail == max) tail = 0;
}
}
vis[u] = false;
head ++;
if(head == max) head = 0;
}
if(dis[en] == inf) return false;
return true;
}
static void end(){
int i, sum = inf;
for(i = en; i != st; i = pre[i])
sum =sum<cap[pre[i]][i]?sum:cap[pre[i]][i];//取小值
for(i = en; i != st; i = pre[i]){//从第1种垃圾开始累加
cap[pre[i]][i] = cap[pre[i]][i]-sum;//已使用
cap[i][pre[i]] = cap[i][pre[i]] +sum;//无效了
ans += cost[pre[i]][i] * sum; // cost[][]记录的为单位流量费用,必须得乘以流量。
// System.out.println(ans);
}
}
public static void main(String[] args){
Scanner ss = new Scanner(System.in);
n = ss.nextInt();//垃圾桶数量
int i,j;
for(i=1;i<=n;i++){
for(j=1;j<=n;j++){
r[i][j+n]=ss.nextInt();
s[i]+=r[i][j+n];//第i个垃圾桶总垃圾
}
}
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
{
cost[i][j+n]=s[i]-r[i][j+n];//除了第j种垃圾 第i个垃圾箱有多少垃圾
cap[i][j+n]=1;
cap[j+n][i]=0;
cost[j+n][i]=-cost[i][j+n];
}
st=2*n+1;
en=2*n+2;
for(i=1;i<=n;i++)
{
cap[st][i]=1;//确认关系
cap[i][st]=0;//清除关系
cost[st][i]=cost[i][st]=0;
cap[i+n][en]=1;
cap[en][i+n]=0;
cost[en][i+n]=cost[i+n][en]=0;
}
ans = 0;
n=2*n+2;
while(spfa()==true)
{
end();
}
System.out.println(ans);
return;
}
}