hrbust 哈理工oj 网线【MST+Prim】

本文介绍使用Prim算法解决特定条件下的最小生成树问题,针对大量数据的有效处理,避免了Kruskal算法可能出现的时间超限问题。通过具体的AC代码示例,详细展示了如何通过Prim算法在确保精度的同时提高计算效率。

网线
Time Limit: 5000 MSMemory Limit: 32768 K
Total Submit: 68(17 users)Total Accepted: 17(15 users)Rating: Special Judge: No
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);
    }
}









评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值