题意:让N只蚂蚁到一棵苹果树,给出N个蚂蚁和N棵苹果树的对应坐标,求权值就是求坐标点之间的距离表示,要求求出最小的距离!
思路:采用最大权完美匹配问题,但是现在这道题是求最小权值,可以将求得的坐标之间的距离取反,取反之后求最大权值就是最小的距离了。
最大权完美匹配:二分图最大匹配是寻找最大匹配数,用匈牙利算法。当连 接的边带有权值时,要寻找匹配后权值和最大的方案,且保证 A 集合中的点均有 B 中的点能匹配。此时问题就转化为二分图最大权完美匹配。
KM 算法核心为: 为每一点添加顶标, 在顶标的限制下用匈牙利算法处理出最大匹配数, 若最大匹配数 =n, 则达到最优解, 输出。否则修改
顶标, 再用匈牙利算法处理, 如此重复。
设二分图的两部分点集分别为 X={X1,X2,…,Xn}X={X1,X2,…,Xn} 和 Y={Y1,Y2,…,Ym}Y={Y1,Y2,…,Ym}, ⟨Xi,Yj⟩⟨Xi,Yj⟩
的边权为 wij
给两部分点集分别赋点权 {Ai},{Bi}{Ai},{Bi},
使得 Ai+Bj⩾wij,
取等的边的生成子图叫做相等子图。那么相等子图的完美匹配就是最大权匹配。我们需要适当选取权值,使相等子图有完美匹配。
算法步骤:
1.若成功(找到了增广轨),则该点增广完成,进入下一个点的增广
2.若失败(没有找到增广轨),则需要改变一些点的标号,使得图中可行边的数量增加。
操作为:将所有在增广轨中(就是在增广过程中遍历到)的X方点的标号全
部减去一个常数d,所有在增广轨中的Y方点的标号全部加上一个常数d
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<vector>
#include<stack>
#include<iomanip>
#include<cstdio>
#define esp 1e-6
using namespace std;
const int maxx=105;
const int maxn=10005;
const int inf=0x3f3f3f3f;
double lx[maxx],ly[maxx];
int visx[maxx],visy[maxx];
double w[maxx][maxx];
int linker[maxx];
double slack[maxx];
int n,m,k;
struct node{
double x,y;
}num[maxx],e[maxx];
double Dist(node a,node b){
double x=a.x-b.x;
double y=a.y-b.y;
return sqrt(x*x+y*y);
}
void init(){
memset(linker,0,sizeof(linker));
memset(w,0,sizeof(w));
}
int Find(int x){
visx[x]=1;
for(int y=1;y<=n;y++){
if(visy[y]==0){
double temp=abs(lx[x]+ly[y]-w[x][y]);
if(temp<=esp){
visy[y]=1;
if(linker[y]==0||Find(linker[y])){
linker[y]=x;
return 1;
}
}else{
slack[y]=min(slack[y],temp);
}
}
}
return 0;
}
void KM(){
memset(ly,0,sizeof(ly));
for(int i=1;i<=n;i++){
lx[i]=-inf;
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(lx[i]<w[i][j]){
lx[i]=w[i][j];
}
}
}
for(int k=1;k<=n;k++){
for(int i=1;i<=n;i++){
slack[i]=inf;
}
while(true){
memset(visx,0,sizeof(visx));
memset(visy,0,sizeof(visy));
if(Find(k))break;
double d=inf;
for(int i=1;i<=n;i++){
if(visy[i]==0){
d=min(d,slack[i]);
}
}
for(int i=1;i<=n;i++){
if(visx[i]==1)lx[i]-=d;
if(visy[i]==1)ly[i]+=d;
else{
slack[i]-=d;
}
}
}
}
}
int main(){
while(scanf("%d",&n)!=EOF){
init();
for(int i=1;i<=n;i++){
scanf("%lf %lf",&num[i].x,&num[i].y);
}
for(int i=1;i<=n;i++){
scanf("%lf %lf",&e[i].x,&e[i].y);
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
w[i][j]=-1.0*Dist(num[i],e[j]);
}
}
KM();
int t[maxx];
memset(t,0,sizeof(t));
for(int i=1;i<=n;i++){
t[linker[i]]=i;
}
for(int i=1;i<=n;i++){
cout<<t[i]<<endl;
}
}
return 0;
}