题目描述:
给定平面上N个城市的位置,计算连接这N个城市所需线路长度总和的最小值。
输入描述:
输入文件中包含多个测试数据。每个测试数据的第1行为一个正整数N,0《=N《=100,代表需要连接的城市数目;接下来有N行,每行为两个实数X和Y,-10000《=X,Y《=10000,表示每个城市的X坐标和Y坐标。输入文件中最后一行为N=0,代表输入结束。
输出描述:
对输入文件中每个测试数据,计算连接所有城市所需线路长度总和的最小值。每对城市之间的线路为连接这两个城市的直线。对于求得的值精确到小数点后两位有效数字。
代码:
kryskal算法:
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<queue>
#include<iostream>
#include<algorithm>
using namespace std ;
int m , n ;
double x[101], y[101], ans;
int pre[5000];
typedef struct
{
int x,y;
double w;
}node;
node edge[5000];
int cmp(node a, node b) //从小到大排序
{
return a.w<b.w;
}
int find(int t) //递归找到其 父节点,即当前顶点属于哪个集合
{
return t==pre[t] ? t:find(pre[t]) ;
}
void hebing(int x,int y) //两个不同集合的合并,将y的父节点更新为x;即把两棵树合并为一颗
{
pre[y]=x ;
}
void Kruskal()
{
int i,j,x1,x2;
for( i = 0 ; i < n;i++) //初始化,设定 每个顶点都为一个独立的集合,父节点是自己本身
pre[i]=i ;
for( i = 0 ; i<m ; i++ )
{
x1=find(edge[i].x);
x2=find(edge[i].y);
if(x1!=x2) //a==b说明边的两个顶点一属于同一颗树, //将a的父节点更新为b,从而将树a,b合并成一棵树
{
hebing(x1,x2);
ans += edge[i].w; //将边的权值加到ans当中
}
}
}
int main()
{
int T = 0;
while(scanf("%d", &n), n) {
ans = 0;
for(int i = 0; i < n; i++) {
scanf("%lf %lf", &x[i], &y[i]);
}
m = 0;ans=0;
for(int i = 0; i < n; i++) {
for(int j = i+1; j < n; j++) {
edge[m].x = i;
edge[m].y = j;
edge[m].w = sqrt((x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]));
m++;
}
}
sort(edge,edge+m,cmp);
Kruskal();
if( T ) printf("\n");
printf("Case #%d:\n", ++T);
printf("The minimal distance is: %.2lf\n", ans);
}
return 0;
}
Prim算法:
- #include<stdio.h>
- #include<stdlib.h>
- #include<math.h>
- #include<string.h>
- const double INF = 99999999;
- double dist[101];
- double mat[101][101];
- int flag[101];
- struct point
- {
- double x,y;
- } a[101],t;
- int main(void)
- {
- int n,i,j,now,start=1;
- double min,sum;
- while( scanf("%d",&n) && n )
- {
- for( i = 1; i <= n; i++ )
- scanf("%lf%lf",&a[i].x,&a[i].y);
- for( i = 1; i <= n; i++ )
- for( j = 1; j <= n; j++ )
- {
- if( i==j ) mat[i][j] = 0;
- else //用邻街矩阵保存边的取值
- {
- mat[i][j] = sqrt((a[i].x-a[j].x)*(a[i].x-a[j].x)
- +(a[i].y-a[j].y)*(a[i].y-a[j].y));
- }
- }
- for( i = 1; i <= n; i++)
- {
- dist[i] = INF;
- flag[i] = 0;
- }
- dist[now=1] = 0;
- flag[1] =1; //标记节点是否放入集合
- for( i= 1,sum=0; i <n ;i++)
- {
- for( j = 1; j <= n; j++) //入选的节点更新未入选的节点
- if( !flag[j] && dist[j] > mat[now][j] ) //mat[now][j] 课理解为now点到J点的权值 dist[j] = mat[now][j];
- for( j = 1,min = INF; j <= n; j++) //选出最小的边的权值的节点
- if( !flag[j] && dist[j] < min )
- min = dist[now = j];
- flag[now]=1; //标记节点已加入集合
- sum += min;
- }
- if( start == 1) printf("Case #%d:/n",start++);
- else printf("/nCase #%d:/n",start++);
- printf("The minimal distance is: %.2lf/n",sum);
- }
- return 0;
- }