zoukankan      html  css  js  c++  java
  • 题解 UVA1411 【Ants】

    题目链接

    蒟蒻来写一篇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
    ",match[i]);
    		}//输出结果
    	}
        return 0;
    }
    

    $ Large exttt{My} exttt{Blog}$

  • 相关阅读:
    解决input获取焦点时底部菜单被顶上来问题
    JavaScript学习笔记
    JavaScript表单验证
    js 中{},[]中括号,大括号使用详解
    陀飞轮
    娱乐天空
    左右手
    软测 学习
    git 学习
    spring boot 学习
  • 原文地址:https://www.cnblogs.com/juruoyqr/p/11518067.html
Copyright © 2011-2022 走看看