zoukankan      html  css  js  c++  java
  • 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
    ",match[i]);
        }
        return 0;
    }
  • 相关阅读:
    Lintcode415-Valid Palindrome-Medium
    Lintcode455-StudentID-Easy
    Lintcode241-String to Integer
    Lintcode521-Remove Duplicate Numbers in Array-Easy
    Lintcode214-Max of Array-Naive
    面试一个小公司,TPM相关概念
    C#, introduction, general
    make命令和makefile
    OS_Architecture_MemoryHierarchy
    Leecode_98_Validate_Binary_Search_Tree
  • 原文地址:https://www.cnblogs.com/wangfang20/p/3195836.html
Copyright © 2011-2022 走看看