POJ 3565 Ants【KM】

题意: 有 N 个蚂蚁,N 个苹果,要在每个蚂蚁和一个相应的苹果之间连边,问如何给蚂蚁分配苹果,可以使这些边不相交。

分析:

应为在最小权值匹配的情况下满足没有边相交,可以简单证明,假设最小完备匹配中有两条线段AC和BD相交于

点E,此时我们可以不连接AC和BD而去连接AD和BC,由于AE+DE>AD和BE+CE>BC,所有我们可以得出新

连接的边的权值和一定比原来的边的权值和小,这样就可以得到一种权值和更小的匹配,这原来的匹配是最小带

权和的匹配矛盾, 因此最小带权和的匹配中不会出现有两条线段相交的情况。 

code:

#include<stdio.h>
#include<string.h>
#include<math.h>
#define clr(x)memset(x,0,sizeof(x))
const double INF=99999999.0;
double map[102][102];
struct node
{
    double x,y;
}an[102],ap[102];
int link[102];
int sx[102],sy[102];
double lx[102],ly[102];
int n;
bool judge(int v,int i)  
{  
    double esp;  
    esp=0.0001;  
    double r=lx[v]+ly[i];  
    double z=map[v][i];  
    if(abs(r-z)<=esp)  
        return true;  
    else  
        return false;  
} 
int find(int x)
{
    sx[x]=1;
    int i;
    for(i=1;i<=n;i++)
        if(!sy[i]&&judge(x,i))
        {
            sy[i]=1;
            if(link[i]==0||find(link[i]))
            {
                link[i]=x;
                return 1;
            }
        }
    return 0;
}
void KM()
{
    clr(ly);
    int v,i,j;
    double dmin;
    for(i=1;i<=n;i++)
        for(j=1;j<=n;j++)
            map[i][j]=-map[i][j];    
    for(i=1;i<=n;i++)
        lx[i]=INF;
    clr(link);
    for(v=1;v<=n;v++)
    {
        clr(sx);   clr(sy);
        while(1)
        {
            if(find(v))
                break;
            dmin=INF;
            for(i=1;i<=n;i++)
                if(sx[i])
                    for(j=1;j<=n;j++)
                        if(!sy[j]&&lx[i]+ly[j]-map[i][j]<dmin)
                            dmin=lx[i]+ly[j]-map[i][j];
            for(i=1;i<=n;i++)
            {
                if(sx[i]){  lx[i]-=dmin;   sx[i]=0;  }
                if(sy[i]){  ly[i]+=dmin;   sy[i]=0;  }
            }
        }
    }
}
double dis(node a,node b)
{
    return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
int main()
{
    int i,j;
    while(scanf("%d",&n)!=EOF)
    {
        for(i=1;i<=n;i++)
            scanf("%lf%lf",&an[i].x,&an[i].y);
        for(i=1;i<=n;i++)
            scanf("%lf%lf",&ap[i].x,&ap[i].y);
        for(i=1;i<=n;i++)
            for(j=1;j<=n;j++)
                map[i][j]=dis(ap[i],an[j]);
        KM();
        for(i=1;i<=n;i++)
            printf("%d\n",link[i]);
    }
    return 0;
}

 

posted @ 2012-07-23 19:05  'wind  阅读(252)  评论(0编辑  收藏  举报