题目链接: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; }
版权声明:本文为博主原创文章,未经博主允许不得转载。
hdu 1162 Eddy's picture (Kruskal算法,prim算法,最小生成树)
时间: 2024-10-25 10:45:25