zoukankan      html  css  js  c++  java
  • POJ3565Ants(KM算法)

    刘汝佳新书--训练指南

    KM算法,求最佳完美匹配

    题意:给出N个白点和N个黑点,要求用N条不相交的线段把它们连接起来,其中每条线段恰好连接一个白点和一个黑点,每个点恰好连接到一条线段。

    分析:因为有结点黑白两色,我们不难想到构造一个二分图,其中每个白点对应一个X结点,每个黑点对应一个Y结点,每个黑点和每个白点相连,权值等于二者的欧几里德距离。建模后最佳完美匹配就是问题的解。为什么呢?假设在最佳完美匹配中有两条线段a1-b1与a2-b2相交,那么dist(a1,b1)+dist(a2,b2)一定大于dist(a1,b2)+dist(a2,b1),因此如果把这两条改成a1-b2和a2-b1后总长度会变少,与最佳二字矛盾。

    注意:KM算法是求权值和最大的,故需要将距离边成负数即可。并且输入坐标值好像是浮点的。。

    // File Name: 1411.cpp
    // Author: zlbing
    // Created Time: 2013/2/27 21:35:37
    
    #include<iostream>
    #include<string>
    #include<algorithm>
    #include<cstdlib>
    #include<cstdio>
    #include<set>
    #include<map>
    #include<vector>
    #include<cstring>
    #include<stack>
    #include<cmath>
    #include<queue>
    using namespace std;
    #define CL(x,v); memset(x,v,sizeof(x));
    #define INF 0x3f3f3f3f
    #define MAXN 105
    struct point{
        double x,y;
    }Point[MAXN*2];
    double dist(point a,point b)
    {
        return sqrt((double)((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)));
    }
    int Left[MAXN];
    double w[MAXN][MAXN];
    double Lx[MAXN],Ly[MAXN];
    bool S[MAXN],T[MAXN];
    int N;
    bool match(int i)
    {
        S[i]=true;
        for(int j=1;j<=N;j++)if(abs(Lx[i]+Ly[j]-w[i][j])<1e-5&&!T[j])
        {
            T[j]=true;
            if(Left[j]==0||match(Left[j]))
            {
                Left[j]=i;
                return true;
            }
        }
        return false;
    }
    void update(){
        double a=INF;
        for(int i=1;i<=N;i++)if(S[i])
            for(int j=1;j<=N;j++)if(!T[j])
                a=min(a,Lx[i]+Ly[j]-w[i][j]);
        for(int i=1;i<=N;i++){
            if(S[i])Lx[i]-=a;
            if(T[i])Ly[i]+=a;
        }
    }
    void KM()
    {
        for(int i=1;i<=N;i++){
            Left[i]=Lx[i]=Ly[i]=0;
            for(int j=1;j<=N;j++)
            {
                Lx[i]=max(Lx[i],w[i][j]);
            }
        }
        for(int i=1;i<=N;i++){
            for(;;){
                CL(S,0);
                CL(T,0);
                if(match(i))break;
                else update();
            }
        }
    }
    int ans[MAXN];
    int main(){
        while(~scanf("%d",&N))
        {
            double a,b;
            for(int i=1;i<=2*N;i++)
            {
                scanf("%lf%lf",&a,&b);
                Point[i].x=a,Point[i].y=b;
            }
            CL(w,0);
            for(int i=1;i<=N;i++)
                for(int j=1;j<=N;j++)
                    w[i][j]=-dist(Point[i],Point[j+N]);
            KM();
            for(int i=1;i<=N;i++)
                ans[Left[i]]=i;
            for(int i=1;i<=N;i++)
                printf("%d\n",ans[i]);
        }
        return 0;
    }
  • 相关阅读:
    User Contro用法
    IHttpHandler 在SharePoint中的应用
    常用Stsadm 操作,网站备份与还原
    Schedule
    WP7>界面>ListBox数据绑定、图文混编、动态添加行
    WP7>界面>全景视图
    WP7>网络>读取网页源码
    UNIXLINUX编程实践教程>第二章>实例代码注解>who01
    WP7>界面>页面导航、切换及参数传递
    UNIXLINUX编程实践教程>第二章>实例代码注解>more01
  • 原文地址:https://www.cnblogs.com/arbitrary/p/2936008.html
Copyright © 2011-2022 走看看