//注意边要反号
#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstdio>
using namespace std;
const double eps = 1e-8;
struct pointt{
double x, y;
pointt(double x, double y) :x(x), y(y)
{}
pointt()
{}
};
pointt pointx[110], pointy[110];
double map[110][110], valuex[110], valuey[110],slack[110];
int match[110], visitx[110], visity[110];
int n;
double dist(pointt a, pointt b)
{
return -sqrt((a.x - b.x)*(a.x - b.x) + (a.y - b.y)*(a.y - b.y));//这里一定要反号因为这个算法是求得是在有完美匹配时的最大值
}
bool dfs(int num)
{
visitx[num] = 1;
for (int i = 1; i <= n; i++)
{
if (visity[i])continue;//这如果visity[i]=1就不要再dfs了有阔能成环
double t = valuex[num] + valuey[i] -map[num][i];
if (t<=eps)
{
visity[i] = 1;
if (match[i] == -1 || dfs(match[i]))//如果哦visity[i]=0那么他的match的visitx一定也是0
{
match[i] = num;
return true;
}
}
else
slack[i] = min(slack[i], t);
}
return false;
}
void km()
{
for (int k = 1; k <= n; k++)match[k] = -1;
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)slack[j] = 1000000000;
while (1)
{
for (int k = 1; k <= n; k++)visitx[k] = 0, visity[k] = 0;
if (dfs(i))break;
double d = 8000000000;
for (int k = 1; k <= n; k++)
if (!visity[k])
d = min(slack[k], d);
for (int k = 1; k <= n; k++)
{
if (visitx[k])
valuex[k] -= d;
if (visity[k])
valuey[k] += d;
//else
//slack[k] -= d;完全可以不要这个,因为反正到时都是取最小
}
}
}
}
int main()
{
scanf("%d", &n);
for (int i = 1; i <= n; i++)
{
scanf("%lf%lf", &pointx[i].x, &pointx[i].y);
}
for (int i = 1; i <= n; i++)
{
scanf("%lf%lf", &pointy[i].x, &pointy[i].y);
}
for (int i = 1; i <= n; i++)
{
valuex[i] = -8000000000;//注意边是负数所以这样初始化
for (int j = 1; j <= n; j++)
{
map[i][j] = dist(pointx[i], pointy[j]);
valuex[i] = max(valuex[i], map[i][j]);
}
}
km();
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
{
if (match[j] == i)
printf("%d\n", j);
}
}
return 0;
}
此题还阔以不用反号,说白了km算法就是贪心加在一定条件下的匹配
所以我们稍稍改一下条件就好让valuex[i]+valuey[j]<=w[i][j]在这个条件下进行匹配,然后贪心地从最小边开始然后慢慢增加。。具体如下:
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
const int MAXN = 110;
const double INF = 0xffffffffffff;
const double eps = 1e-6;
struct Node
{
double x, y;
}Dot1[MAXN], Dot2[MAXN];
double Dist(Node a, Node b)
{
return sqrt((a.x - b.x)*(a.x - b.x) + (a.y - b.y)*(a.y - b.y));
}
int N, NX, NY;
double Map[MAXN][MAXN];
int link[MAXN];
double lx[MAXN], ly[MAXN], slack[MAXN];
int visx[MAXN], visy[MAXN];
int FindPath(int u)
{
visx[u] = 1;
for (int i = 1; i <= NY; ++i)
{
if (visy[i])
continue;
double temp = Map[u][i] - lx[u] -ly[i];
if (fabs(temp) <= eps)
{
visy[i] = 1;
if (link[i] == -1 || (FindPath(link[i])))
{
link[i] = u;
return 1;
}
}
else
{
if (slack[i] > temp)
slack[i] = temp;
}
}
return 0;
}
void KM()
{
for (int i = 0; i <= NX; i++)lx[i] = 8000000000;
memset(ly, 0, sizeof(ly));
memset(link, -1, sizeof(link));
for (int i = 1; i <= NX; ++i)
{
for (int j = 1; j <= NY; ++j)
{
lx[i] = min(lx[i], Map[i][j]);
}
}
for (int i = 1; i <= NX; ++i)
{
for (int j = 1; j <= NY; ++j)
slack[j] = INF;
while (1)
{
memset(visx, 0, sizeof(visx));
memset(visy, 0, sizeof(visy));
if (FindPath(i))
break;
double d = INF;
for (int j = 1; j <= NY; ++j)
if (!visy[j] && d > slack[j])
d = slack[j];
for (int j = 1; j <= NX; ++j)
if (visx[j])
lx[j] += d;
for (int j = 1; j <= NY; ++j)
{
if (visy[j])
ly[j] -= d;
else
slack[j] -= d;
}
}
}
}
int main()
{
int N;
scanf("%d", &N);
memset(Map, 0, sizeof(Map));
for (int i = 1; i <= N; ++i)
scanf("%lf%lf", &Dot1[i].x, &Dot1[i].y);
for (int i = 1; i <= N; ++i)
scanf("%lf%lf", &Dot2[i].x, &Dot2[i].y);
for (int i = 1; i <= N; ++i)
for (int j = 1; j <= N; ++j)
{
Map[i][j] = Dist(Dot1[i], Dot2[j]);
//cout << Map[i][j] << endl;
}
NX = NY = N;
KM();
for (int i = 1; i <= N; ++i)
{
for (int j = 1; j <= N; ++j)
{
if (link[j] == i)
{
printf("%d\n", j);
break;
}
}
}
return 0;
}