KM练习
n个点找最多的不相交线段。
可以证明最短路匹配可以满足要求。
这个过了
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;
int n;
double fmap[1000][1000];
int visx[1000],visy[1000],link[1000];
double lx[1000],ly[1000],slack[1000],d;
struct tree
{
double x,y;
}t[1000];
struct ants
{
double x,y;
}an[1000];
double dis(tree a,ants b)
{
double t;
t=(a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y);
return sqrt(t);
}
void build()
{
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
fmap[i][j]=-dis(t[i],an[j]);
}
}
}
int dfs(int k)
{
visx[k]=1;
for(int i=0;i<n;i++)
{
if(visy[i])
{
continue;
}
double t=lx[k]+ly[i]-fmap[k][i];
if(fabs(t)<1e-5)
{
visy[i]=1;
if(link[i]==-1||dfs(link[i]))
{
link[i]=k;
return 1;
}
}
else
{
// if(d>t)
// {
// d=t;
// }
if(slack[i]>t)
{
slack[i]=t;
}
}
}
return 0;
}
void KM()
{
memset(lx,0,sizeof lx);
memset(ly,0,sizeof ly);
memset(link,-1, sizeof link);
for(int i=0;i<n;i++)
{
lx[i]=-999999.0;
for(int j=0;j<n;j++)
{
if(fmap[i][j]>lx[i])
{
lx[i]=fmap[i][j];
}
}
}
for(int k=0;k<n;k++)
{
for(int i=0;i<n;i++)
{
slack[i]=999999.0;
}
while(1)
{
memset(visx,0,sizeof visx);
memset(visy,0,sizeof visy);
d=9999999.0;
if(dfs(k))
{
break;
}
for(int i=0;i<n;i++)
{
if(!visy[i]&&d>slack[i])
{
d=slack[i];
}
}
for(int i=0;i<n;i++)
{
if(visx[i])
{
lx[i]-=d;
}
}
for(int i=0;i<n;i++)
{
if(visy[i])
{
ly[i]+=d;
}
else
{
slack[i]-=d;
}
}
}
}
}
int main()
{
// freopen("in","r",stdin);
while(scanf("%d",&n)!=EOF)
{
for(int i=0;i<n;i++)
{
scanf("%lf%lf",&an[i].x,&an[i].y);
}
for(int i=0;i<n;i++)
{
scanf("%lf%lf",&t[i].x,&t[i].y);
}
build();
KM();
for(int i=0;i<n;i++)
{
printf("%d\n",link[i]+1);
}
}
return 0;
}
这个tle了
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;
int n;
double fmap[1000][1000];
int visx[1000],visy[1000],link[1000];
double lx[1000],ly[1000],slack[1000],d;
struct tree
{
double x,y;
}t[1000];
struct ants
{
double x,y;
}an[1000];
double dis(tree a,ants b)
{
double t;
t=(a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y);
return sqrt(t);
}
void build()
{
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
fmap[i][j]=-dis(t[i],an[j]);
}
}
}
int dfs(int k)
{
visx[k]=1;
for(int i=0;i<n;i++)
{
if(visy[i])
{
continue;
}
double t=lx[k]+ly[i]-fmap[k][i];
if(fabs(t)<1e-5)
{
visy[i]=1;
if(link[i]==-1||dfs(link[i]))
{
link[i]=k;
return 1;
}
}
else
{
if(d>t)
{
d=t;
}
// if(slack[i]>t)
// {
// slack[i]=t;
// }
}
}
return 0;
}
void KM()
{
memset(lx,0,sizeof lx);
memset(ly,0,sizeof ly);
memset(link,-1, sizeof link);
// for(int i=0;i<n;i++)
// {
// lx[i]=-999999.0;
// for(int j=0;j<n;j++)
// {
// if(fmap[i][j]>lx[i])
// {
// lx[i]=fmap[i][j];
// }
// }
// }
for(int k=0;k<n;k++)
{
// for(int i=0;i<n;i++)
// {
// slack[i]=999999.0;
// }
while(1)
{
memset(visx,0,sizeof visx);
memset(visy,0,sizeof visy);
d=9999999.0;
if(dfs(k))
{
break;
}
// for(int i=0;i<n;i++)
// {
// if(!visy[i]&&d>slack[i])
// {
// d=slack[i];
// }
// }
for(int i=0;i<n;i++)
{
if(visx[i])
{
lx[i]-=d;
}
}
for(int i=0;i<n;i++)
{
if(visy[i])
{
ly[i]+=d;
}
// else
// {
// slack[i]-=d;
// }
}
}
}
}
int main()
{
// freopen("in","r",stdin);
while(scanf("%d",&n)!=EOF)
{
for(int i=0;i<n;i++)
{
scanf("%lf%lf",&an[i].x,&an[i].y);
}
for(int i=0;i<n;i++)
{
scanf("%lf%lf",&t[i].x,&t[i].y);
}
build();
KM();
for(int i=0;i<n;i++)
{
printf("%d\n",link[i]+1);
}
}
return 0;
}
看了一下discuss 感觉说的有道理!
个人觉得:这样写每次找出来的slack值是不对的,会偏小。因为对于当前visy[y]=0的Y中的点,visy[y]可能会在后来变为1,但是你在dfs的过程中因为当前visy[y]是0而更新了slack的值。