hdu 1162 Eddy's picture (Kruskal算法,prim算法,最小生成树)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1162


【题目大意】

给你n个点的坐标,让你找到联通n个点的一种方法,保证联通的线路最短,典型的最小生成树问题。


方法一 , 通过不断找到最小的边来找到最终结果。

Kruskal 算法

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cmath>
using namespace std;
struct node{
    double a,b;
    int po;
}point[110];
const int maxe = 10010;
struct Edge{
    int v1,v2;
    double length;
}edge[maxe];
bool cmp(const Edge&a, const Edge&b){
    return a.length<b.length;
}
int n; int cnt;
int father[110];
void MakeSet(){
    for(int i=0;i<=n;i++){
        father[i]=i;
    }
}
int Find(int x){
    int xroot = x;
    while(xroot!=father[xroot])
        xroot=father[xroot];
    while(x!=xroot){
        int tmp = father[x];
        father[x]=xroot;
        x = tmp;
    }
    return xroot;
}
void Union(int x,int y){
    int xr=Find(x);
    int yr=Find(y);
    if(xr==yr) return ;
    else{
        father[xr]=yr;
    }
}
void Kruskal(){
    int edgenum=0;
    double ans=0;
    for(int i=0;i<cnt&&edgenum!=n-1;i++){
        if(Find(edge[i].v1)!=Find(edge[i].v2)){
            ans+=edge[i].length;
            Union(edge[i].v1,edge[i].v2);
            edgenum++;
        }
    }
    printf("%.2lf\n",ans);
}
double disc(node x, node y){
    return (double)sqrt((x.a-y.a)*(x.a-y.a)+(x.b-y.b)*(x.b-y.b));
}
int main(){
    double a,b;
    while(cin>>n){
        for(int i=0;i<n;i++){
            cin>>point[i].a>>point[i].b;
            point[i].po=i+1;
        }
        MakeSet();
        cnt=0;
        for(int i=0;i<n;i++){
            for(int j=i+1;j<n;j++){
                double dis= disc(point[i],point[j]); //求出点 与 点 之 间 的距 离, 列出所有的边。
                edge[cnt].v1=point[i].po;
                edge[cnt].v2=point[j].po;
                edge[cnt].length=dis;
                cnt++;
            }
        }
        sort(edge,edge+cnt,cmp);
        Kruskal();
    }
    return 0;
}


方法二 prim算法, 通过不断找到距离 最小生成树所在集合所有点中 距离最小的点。


#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cmath>
#include <vector>
using namespace std;
#define maxn 110
#define INF 0xfffffff
struct node{
	double a,b;
	int po;
}point[maxn];
int n;
struct node2{
	int v;
	double dis;
	node2(int v=0, double dis=0):v(v),dis(dis){}
};
vector <node2> G[maxn]; //用邻接链表储存图
const int maxe = 10010;
bool intree[maxn];
double minDist[maxn];
void init(){
	for(int i=0;i<maxn;i++ ){
		minDist[i]=INF;
		G[i].clear();
		intree[i]=false;
	}
}
double prim(int s){
	intree[s] = true;
	for(int i=0;i<G[s].size();i++){
		int vex = G[s][i].v;
		minDist[vex] = G[s][i].dis; //初始化  , 将与起点相联的 点与起点的距离“显化”
	}
	double ans = 0;
	for(int nodeNum = 1 ;nodeNum<=n-1;nodeNum++){ //还剩下 n-1 个点未找
		double tmpMin = INF;
		int addNode;
		for(int i=1;i<=n;i++){
			if(!intree[i]&&minDist[i]<tmpMin){ //只有经过显化的 且没有入最小生成树的点 才能通过比较
				tmpMin = minDist[i]; //不断更新,找到最短的
				addNode = i;
			}
		}
		intree[addNode] = true; //入树
		ans+=tmpMin; 
		for(int i=0; i < G[addNode].size();i++){ //更新  将新加入节点的 相联节点“显化” 
			int vex = G[addNode][i].v;
			if(!intree[vex]&&G[addNode][i].dis<minDist[vex]) //更新未入最小生成树的节点,与之的最短距离。
				minDist[vex] = G[addNode][i].dis;
		}
	}
	return ans;
}
double disc(node x, node y){
	return (double)sqrt((x.a-y.a)*(x.a-y.a)+(x.b-y.b)*(x.b-y.b));
}
int main(){
	double a,b;
	while(cin>>n){
		for(int i=0;i<n;i++){
			cin>>point[i].a>>point[i].b;
			point[i].po=i+1;
		}
		init();
		for(int i=0;i<n;i++){
			for(int j=i+1;j<n;j++){
				double dis= disc(point[i],point[j]);
				G[point[i].po].push_back(node2(point[j].po,dis));
				G[point[j].po].push_back(node2(point[i].po,dis));
			}
		}
		double ans = prim(1);
		printf("%.2lf\n",ans);
	}
	return 0;
}



你可能感兴趣的:(算法,图论,Prim,kruskal,acm模板)