题目大意:
给出一些二维平面图的点的坐标,要求编程输出如果要把这些点全部用线连起来需要的最短的线的长度。
输入:
第一行输入一个整数N代表点的个数,然后接下来的N*(N-1)/2行每行输入两个数,代表这个点的坐标(横坐标X和纵坐标Y)
输出:
最短线的长度。
解题思路:
这道题理解了题意之后明明觉得很简单但就是不知道怎么做,这道题我用了一个多小时才解出来,但是还不知道对不对。我是这么做的,我用的是kustal算法,首先定义了一个结构体变量Node代表点,内有属性X和Y,代表点的纵、横坐标,还有index,代表点的标号。然后又定义了一个结构体变量Bian,来存储两个点之间的边,内有属性,N1和N2还有length,分别代表这条边的两个端点和长度。当有N个定点的时候我们知道无向完全图有N*(N-1)/2条边。Main主程序刚开始时用一个for循环从1到N输入点的纵横坐标,然后用i去初始化每个点的index。接下来用两层for循环去初始化bian数组,然后根据leng的长度从小到大排序,接下来就是用并查集的方法去进行合并求值,最后输出ans。
感想:
这道题遇到的问题主要有以下几个:
1、不能简单的用i去初始化points数组,我在这里是在Node中加了个index属性作为点的标号,和以前的题统一;
2、在进行并查集合并的时候不能简单的find[x]=y,因为这里的点使用两个数来表示的,因此我是弄了一层for循环找到所有使用过这个点的边,将他们的index值更新,合并到集合中。
3、代码如下:
#include<iostream>
#include<cmath>
#include<algorithm>
using namespace std;
int aa=99999;
struct Node
{
int index;
double x, y;
}point[101];
struct Bian
{
Node n1, n2;
double length;
}bian[101];
int find(int x)
{
if (x!=point[x].index)
point[x].index = find(point[x].index);
return point[x].index;
}
bool cmp(Bian b1, Bian b2)
{
return b1.length < b2.length;
}
int main()
{
int n, m;
double ans = 0;
cin >> n;
m = n*(n - 1) / 2;
int k = 0;
for (int i = 1; i <= n; i++)
{
point[i].index = i;
cin >> point[i].x >> point[i].y;
}
for (int i = 1; i < n; i++)
for (int j = i+1; j <= n; j++)
{
k++;
bian[k].n1 = point[i];
bian[k].n2 = point[j];
bian[k].length = sqrt((point[i].x - point[j].x)*(point[i].x - point[j].x) + (point[i].y - point[j].y)*(point[i].y - point[j].y));
}
sort(bian + 1, bian + m + 1, cmp);
for (int i = 1; i <= m; i++)
{
int x = find(bian[i].n1.index);
int y = find(bian[i].n2.index);
if (x != y)
{
ans += bian[i].length;
for (int i = 1; i <= m; i++)
{
if (bian[i].n1.index == x)
bian[i].n1.index = y;
if (bian[i].n2.index == x)
bian[i].n2.index = y;
}
}
}
cout << ans << endl;
system("pause");
return 0;
}