| 网线 | ||||||
| ||||||
| Description | ||||||
|
试设计一个网络连接某个区域中的一些地点。给定这些地点所在的位置,网线的长度就是两个地点的线段距离,假定,给定的网线可以直接或间接的连接该地区中的所有点,试为这个地区设计一个网络系统,使得该地区所有地点都可以直接或间接的连接,并且使用网线长度最短。 | ||||||
| Input | ||||||
|
输入一个数字n(n<1000),给出这n个点的位置(x,y),即坐标(0≤x<1000,0≤y<1000)。 | ||||||
| Output | ||||||
| 输出网线的最短距离,保留小数点后四位。 | ||||||
| Sample Input | ||||||
|
1 1 1 2 0 0 1 1 3 0 0 0 1 1 1 | ||||||
| Sample Output | ||||||
|
0.0000 1.4142 2.0000 | ||||||
| Author | ||||||
| 彭文文@hrbust |
N的数据范围比较大,克鲁斯卡算法会超时,即使路径压缩了,即使使用快排了,还是会超时,所以被逼无奈,只能用prim来做。
在计算过程中呢,我们需要考虑一个精度问题,我们如果在入图的时候就使用double或者float来写的话,很容易产生精度差,当然就会有wa的可能。
所以我们在计算过程中,入图的时候用int,只有在生成树的过程中加上sqrt(map【i】【j】)就行了,这个时候我们避免了精度差问题,也省略了很多不必要的*1.0之类的步骤。
AC代码:
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <algorithm>
using namespace std;
#define inf 0x6ffffff
struct zuobiao
{
int x,y;
}a[1004];
int vis[1005];//用来表示这个点有没有遍历的到.
int dis[1005];
int map[1005][1005];
int n;
double sum;
int diss(zuobiao a,zuobiao b)
{
return (a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y);
}
void prim()
{
int i,j,k,min;
for(i=2;i<=n;i++)
dis[i]=map[1][i];
vis[1]=1;
for(i=2;i<=n;i++)//经过N次遍历一定能遍历所有的点 也就是完成了最终目标.
{
min=inf;
for(j=1;j<=n;j++)
{
if(vis[j]==0 &&dis[j]<min)
{
min=dis[j];
k=j;
}
}
if(min==inf)
break;
vis[k]=1;
sum+=sqrt(1.0*min);//完成了一次权值加和.
for(j=2;j<=n;j++)
{
if(vis[j]==0 &&dis[j]>map[k][j])
dis[j]=map[k][j];
}//更新最优解.
}
}
int main()
{
while(~scanf("%d",&n))
{
memset(vis,0,sizeof(vis));
memset(dis,0,sizeof(dis));
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
map[i][j]=inf*1.0;
}
}
for(int i=1;i<=n;i++)
{
scanf("%d%d",&a[i].x,&a[i].y);
for(int j=1;j<i;j++)
{
map[i][j]=map[j][i]=diss(a[i],a[j]);
}
}
sum=0;
prim();
printf("%.4lf\n",sum);
}
}
本文介绍使用Prim算法解决特定条件下的最小生成树问题,针对大量数据的有效处理,避免了Kruskal算法可能出现的时间超限问题。通过具体的AC代码示例,详细展示了如何通过Prim算法在确保精度的同时提高计算效率。

732

被折叠的 条评论
为什么被折叠?



