http://poj.org/problem?id=3565
题意:
有N只ants和N棵tree,要求一种ants和tree的匹配方案,使得ant和tree之间的匹配线段互不相交。
思路:
KM求距离权值和最小的完备匹配,即我们可以证明距离权值和最小的完备匹配一定是不会出现
两条线段相交的情况。下面给出一个证明:我们假设最小完备匹配中有两条线段AC和BD相交于
点E,此时我们可以不连接AC和BD而去连接AD和BC,由于AE+DE>AD(三角形的性质)和BE+
CE>BC,所有我们可以得出新连接的边的权值和一定比原来的边的权值和小,这样就可以得到
一种权值和更小的匹配,这原来的匹配是最小带权和的匹配矛盾, 因此最小带权和的匹配中不会
出现有两条线段相交的情况。
代码:
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<stdlib.h>
#define CC(m,what) memset(m ,what , sizeof(m))
#define FF(i , CH) for(int i=0;i<CH;i++)
const int MAXN = 110 ;
const int inf = (1<<30) ;
const double eps = 1e-6 ;
int N ;
int x1[MAXN] , yy1[MAXN] , x2[MAXN] , yy2[MAXN] ;
double w[MAXN][MAXN] ;
void calc(){
FF(i , N)
FF( j , N )
w[i][j] = -sqrt( (x2[i] - x1[j])*(x2[i] - x1[j])*1.0 + (yy2[i] - yy1[j])*(yy2[i] - yy1[j])*1.0 );
}
int match[MAXN] ;
double lx[MAXN] ,ly[MAXN] , slack[MAXN];
bool sx[MAXN] ,sy[MAXN] ;
bool dfs(int u){
sx[u] = 1 ;
FF(v , N){
if( sy[v]) continue ;
double t = lx[u] + ly[v] - w[u][v] ;
if( fabs(t)<eps ){
sy[v] = 1 ;
if( match[v]==-1 || dfs(match[v])){
match[v] = u ;
return true ;
}
}
else if( slack[v] > t)
slack[v] = t ;
}
return false ;
}
void KM(){
CC(match , -1) ;
FF(i , N){
lx[i] = -inf ;
FF( j , N ){
if(lx[i] < w[i][j] )
lx[i] = w[i][j] ;
}
}
FF(i , N){
FF( j , N )
slack[j] = inf ;
while(1){
CC(sx, 0) ; CC(sy,0) ;
if( dfs(i) ) break ;
double d = inf ;
FF(j , N){
if( !sy[j] && d>slack[j])
d = slack[j] ;
}
FF(j , N){
if(sx[j])
lx[j] -= d ;
}
FF(j ,N){
if( sy[j] )
ly[j] += d;
else
slack[j] -= d ;
}
}
}
FF(i , N){
printf("%d\n",match[i] + 1) ;
}
}
int main(){
while(scanf("%d",&N) == 1){
FF(i ,N) scanf("%d%d",&x1[i] ,&yy1[i]);
FF(i ,N) scanf("%d%d",&x2[i] ,&yy2[i]);
calc() ;
KM() ;
}
return 0;
}