poj 3565 二分图最优匹配

思路:

将ant与tree之间用距离来做权值,求最小权匹配就可以了。可以想到,如果有两条线段相交,那么将这两个线段交换一个顶点,使其不相交,其权值和一定会更小。

就像斜边永远比直角边长一样的道理。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define Maxn 110
#define Eps 0.000001
using namespace std;
int sx[Maxn],sy[Maxn],match[Maxn],n;
double lx[Maxn],ly[Maxn],weight[Maxn][Maxn],slack[Maxn];
struct Point{
    double x,y;
}tree[Maxn],ant[Maxn];
double Dis(Point a,Point b)
{
    return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
int dfs(int u)
{
    int i;
    sx[u]=1;
    for(i=1;i<=n;i++)
    {
        if(!sy[i]&&(lx[u]+ly[i]-weight[u][i]<Eps))
        {
            sy[i]=1;
            if(match[i]==-1||dfs(match[i]))
            {
                match[i]=u;
                return 1;
            }
        }
        if(!sy[i]&&slack[i]>lx[u]+ly[i]-weight[u][i])
            slack[i]=lx[u]+ly[i]-weight[u][i];
    }
    return 0;
}
int bestmatch()
{
    int i,j;
    for(i=1;i<=n;i++)
    {
        lx[i]=-10000000;
        ly[i]=0;
        for(j=1;j<=n;j++)
        {
            weight[i][j]=-weight[i][j];
            lx[i]=max(lx[i],weight[i][j]);
        }
    }
    memset(match,-1,sizeof(match));
    //cout<<n<<endl;
    for(i=1;i<=n;i++)
    {    
        for(j=0;j<=n;j++)
            slack[j]=10000000;
    while(1)
    {
        memset(sx,0,sizeof(sx));
        memset(sy,0,sizeof(sy));
        if(dfs(i))
            break;
        double dx=10000000;
        for(j=1;j<=n;j++)
            if(!sy[j])
            dx=min(dx,slack[j]);//每次找的都是不在交错路径上的点,故slack[i]==0的情况不会被遍历
        for(j=1;j<=n;j++)
        {
            if(sx[j])
                lx[j]-=dx;
            if(sy[j])
                ly[j]+=dx;
            else
                slack[j]-=dx;//由于X(i)已经更新过了,故每个slack[i]要减去dx,否则下次循环就会多减
        }
    }
    }
    int ans=0;
    for(i=1;i<=n;i++)
        ans+=weight[match[i]][i];
    return -ans;
}
int main()
{
    int i,j;
    while(scanf("%d",&n)==1)
    {
        for(i=1;i<=n;i++)
            scanf("%lf%lf",&ant[i].x,&ant[i].y);
        for(i=1;i<=n;i++)
            scanf("%lf%lf",&tree[i].x,&tree[i].y);
        for(i=1;i<=n;i++)
            for(j=1;j<=n;j++)
                weight[i][j]=Dis(tree[i],ant[j]);
        bestmatch();
        for(i=1;i<=n;i++)
            printf("%d\n",match[i]);
    }
    return 0;
}

 

posted @ 2013-07-17 14:52  fangguo  阅读(190)  评论(0编辑  收藏  举报