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;

}

 

你可能感兴趣的:(poj)