POJ_3565 Ants KM匹配

来源:互联网 发布:任务管理器修复软件 编辑:程序博客网 时间:2024/05/21 19:05

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;}