• 训练指南 UVALive



    layout: post
    title: 训练指南 UVALive - 4043(二分图匹配 + KM算法)
    author: "luowentaoaa"
    catalog: true
    mathjax: true
    tags:
    - 二分图匹配
    - 图论
    - 训练指南


    Ants

    UVALive - 4043

    题意

    给你n个白点和n个黑点的平面坐标,要求用n条不相交的线连起来,每条线段连一个白点和黑点,每个点连一条线,也就是匹配。让你输出第i个白点所对应的黑点。

    思路

    二分图完美匹配问题。但是题目中有个线段不相交,怎么办?其实这个最佳完美匹配就是答案了。最佳完美匹配是权值和最大,那么我们就把两两点线段的权值搞成他们距离的负数即可。这样就不可能有相交的了。为什么?因为假设有相交,a1-b2,a2-b1,而dist(a1,b1)+dist(a2,b2) 肯定比前面交叉的小,画个四边形就很清楚了,那么负数就是大了,也就是说交叉的在我们设计的负权那里是小的,所以就是最佳,也就是不可能有交叉的。

    这样分析清楚了之后,就只要直接套用KM就OK了!

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const ll mod=998244353;
    const int maxn=1e2+50;
    const double inf=999999999999999.;
    const double eps=1e-5;
    struct node{
        double x,y;
    }white[150],black[150];
    double g[150][150];
    int nx,ny;
    bool visx[maxn],visy[maxn];
    double slack[maxn];
    int linker[maxn];
    double lx[maxn],ly[maxn];
    bool dfs(int x){
        visx[x]=true;
        for(int y=0;y<ny;y++){
            if(visy[y])continue;
            double tmp=lx[x]+ly[y]-g[x][y];
            if(fabs(tmp)<eps){
                visy[y]=true;
                if(linker[y]==-1||dfs(linker[y])){
                    linker[y]=x;return true;
                }
            }
            else if(slack[y]>tmp)slack[y]=tmp;
        }
        return false;
    }
    int KM(){
        memset(linker,-1,sizeof(linker));
        memset(ly,0,sizeof(ly));
        for(int i=0;i<nx;i++){
            lx[i]=-inf;
            for(int j=0;j<ny;j++){
                if(g[i][j]>lx[i])lx[i]=g[i][j];
            }
        }
        for(int x=0;x<nx;x++){
            for(int i=0;i<ny;i++)slack[i]=inf;
            while(true){
                memset(visx,false,sizeof(visx));
                memset(visy,false,sizeof(visy));
                if(dfs(x))break;
                double d=inf;
                for(int i=0;i<ny;i++)
                    if(!visy[i]&&d>slack[i])d=slack[i];
                for(int i=0;i<nx;i++)
                    if(visx[i])lx[i]-=d;
                for(int i=0;i<ny;i++)
                    if(visy[i])ly[i]+=d;
                    else slack[i]-=d;
            }
        }
        int res=0;
        for(int i=0;i<ny;i++)
            if(linker[i]!=-1)res+=g[linker[i]][i];
        return res;
    }
    
    double dis(node a,node b){
        return double(sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)));
    }
    int n;
    int main()
    {
        std::ios::sync_with_stdio(false);
        std::cin.tie(0);
        std::cout.tie(0);
        int first=0;
        while(cin>>n){
            nx=ny=n;
            if(first)cout<<endl;
            first=1;
            for(int i=0;i<n;i++){
                cin>>white[i].x>>white[i].y;
            }
            for(int i=0;i<n;i++){
                cin>>black[i].x>>black[i].y;
            }
            for(int i=0;i<n;i++)for(int j=0;j<n;j++)g[i][j]=-dis(black[i],white[j]);
            KM();
            for(int i=0;i<n;i++)cout<<linker[i]+1<<endl;
        }
        return 0;
    }
    
    
  • 相关阅读:
    在CentOS中配置DNS服务器
    CENTOS5.3 64位 VNC远程控制Centos 安装配置
    Windows Server 2003 FTP服务器配置详解 20091210 14:23:36| 分类: 服务器 | 标签: |字号大
    Centos 5.1 sendmail邮件服务器安装及配置
    DNS安装配置全过程
    tomcat多域名设置
    tomcat6 优化初步
    让CentOS自动备份mysql数据库 不指定
    开通企业邮箱之前,请登录您企业网站的域名注册服务商的域名管理平台,进行DNS配置及指向设置,谢谢您的配合
    18.3.2 在不同主机上使用 RMAN 备份建立物理备用数据库
  • 原文地址:https://www.cnblogs.com/luowentao/p/10350977.html
Copyright © 2020-2023  润新知