首页 > 其他 > 详细

题解 UVA1411 【Ants】

时间:2019-09-14 00:49:22      阅读:77      评论:0      收藏:0      [点我收藏+]

题目链接

蒟蒻来写一篇KM算法的题解。

首先,如果所有线段不相交,那么线段长度之和一定最小。证明很简单,在这里不再赘述。(提示:三角形两边之和大于第三边)

那么这道题就转化为了一道带权二分图匹配问题,可以使用费用流求解。又由于黑白点数相同,所以带权最大匹配一定是完备匹配,故可以用KM算法求解。

若不会KM算法,请到这里学习。

然后就把KM算法的板子改一下,在每个黑点与白点之间连一条权值为距离的边,就可以A了。

代码:

#include<bits/stdc++.h>
using namespace std;

const double INF=1e9;

double Map[101][101],la[101],lb[101],va[101],vb[101],upd[101],delta;//一定要开double
int match[101],n;

bool dfs(int x){
    va[x]=1;
    for(int i=1;i<=n;i++){
        if(!vb[i]){
            if(fabs(la[x]+lb[i]-Map[x][i])<=0.0001){//注意精度
                vb[i]=1;
                if(!match[i]||dfs(match[i])){
                    match[i]=x;
                    return true;
                }
            }
            else{
                upd[i]=min(upd[i],la[x]+lb[i]-Map[x][i]);
            } 
        }
    }
    return false;
}

void KM(){//KM算法,不多解释
    for(int i=1;i<=n;i++){
        la[i]=-INF;
        lb[i]=0;
        for(int j=1;j<=n;j++){
            la[i]=max(la[i],Map[i][j]);
        }
    }
    
    for(int i=1;i<=n;i++){
        while(1){
            memset(va,0,sizeof(va));
            memset(vb,0,sizeof(vb));
            for(int i=1;i<=n;i++){
                upd[i]=INF;
            }
            if(dfs(i)){
                break;
            }
            delta=INF;
            for(int j=1;j<=n;j++){
                if(!vb[j]) delta=min(delta,upd[j]);
            }
            for(int j=1;j<=n;j++){
                if(va[j]) la[j]-=delta;
                if(vb[j]) lb[j]+=delta;
            }
        }
    }
}

void init(){
    memset(Map,0,sizeof(Map));
    memset(match,0,sizeof(match));
}

int main() {
    double x1[101],x2[101],y1[101],y2[101];
    while(scanf("%d",&n)!=EOF){
        init();
        
        for(int i=1;i<=n;i++){
            scanf("%lf %lf",&x2[i],&y2[i]);
        }
        for(int i=1;i<=n;i++){
            scanf("%lf %lf",&x1[i],&y1[i]);
        }
        
        for(int i=1;i<=n;++i){
            for(int j=1;j<=n;++j){
                Map[i][j]=-double(sqrt((x1[i]-x2[j])*(x1[i]-x2[j])+(y1[i]-y2[j])*(y1[i]-y2[j])));
            }
        }//计算所有黑白点之间的距离,并连边
        KM();//KM求带权匹配
        for(int i=1;i<=n;i++){
            printf("%d\n",match[i]);
        }//输出结果
    }
    return 0;
}

$ \LARGE\texttt{\color{red} My}\texttt{\color{blue} Blog}$

题解 UVA1411 【Ants】

原文:https://www.cnblogs.com/juruoyqr/p/11518067.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!