Problem
给定一些黑点白点,要求一个黑点连接一个白点,并且所有线段都不相交。
Solution
- 黑白点之间的两两匹配可以看成二分图完美匹配。
- 对于任意一组匹配a-b,c-d,如果两者相交,则一定有dis(ab)+dis(cd)>dis(ad)+dis(cb),因此可以负的欧几里得距离建图,跑km求最小完美匹配即可。
Code
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
using namespace std;
const int inf = 1e9;
const int maxn = 105;
const double eps = 1e-6;
int n,px[maxn],py[maxn],pre[maxn];
int vx[maxn],vy[maxn],x[maxn*2],y[maxn*2];
double e[maxn][maxn],lx[maxn],ly[maxn],slack[maxn];
double dis(int a,int b,int c,int d)
{
return sqrt((a-c)*(a-c)+(b-d)*(b-d));
}
bool isequ(double a,double b)
{
return fabs(a-b)<eps;
}
void aug(int s)
{
int t;
while(s)
{
t = px[pre[s]];
px[pre[s]] = s;
py[s] = pre[s];
s = t;
}
}
void bfs(int s)
{
memset(vx,0,sizeof(vx));
memset(vy,0,sizeof(vy));
for(int i=1;i<=n;i++)
slack[i] = inf;
queue<int>q;
q.push(s);
while(1)
{
while(!q.empty())
{
int u = q.front();q.pop();
vx[u] = 1;
for(int i=1;i<=n;i++)if(!vy[i])
{
if(lx[u]+ly[i]-e[u][i]<slack[i])
{
slack[i] = lx[u]+ly[i]-e[u][i];
pre[i] = u;
if(isequ(slack[i],0))
{
vy[i] = 1;
if(!py[i])
{
aug(i);
return ;
}
else
q.push(py[i]);
}
}
}
}
double d = inf;
for(int i=1;i<=n;i++)if(!vy[i])
d = min(d,slack[i]);
for(int i=1;i<=n;i++)
{
if(vx[i]) lx[i]-=d;
if(vy[i]) ly[i]+=d;
else
slack[i]-=d;
}
for(int i=1;i<=n;i++)if(!vy[i])
{
if(isequ(slack[i],0))
{
vy[i] = 1;
if(!py[i])
{
aug(i);
return ;
}
else
q.push(py[i]);
}
}
}
}
void init()
{
for(int i=1;i<=n;i++)
lx[i]=ly[i]=0;
memset(px,0,sizeof(px));
memset(py,0,sizeof(py));
memset(pre,0,sizeof(pre));
}
int main()
{
// freopen("1.txt","w",stdout);
bool blank = 0;
while(cin>>n)
{
if(blank) cout<<endl;
init();
for(int i=1;i<=(n<<1);i++)
scanf("%d%d",&x[i],&y[i]);
for(int i=1;i<=n;i++)
{
for(int j=n+1;j<=(n<<1);j++)
e[i][j-n]=-dis(x[i],y[i],x[j],y[j]);
}
for(int i=1;i<=n;i++)
lx[i] = -inf;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
lx[i]=max(lx[i],e[i][j]);
for(int i=1;i<=n;i++)
bfs(i);
for(int i=1;i<=n;i++)
cout<<px[i]<<endl;
blank = 1;
}
return 0;
}