[Usaco2007 Dec]Building Roads 修建道路

这篇博客讨论了如何运用Prim算法来解决农民John在修建农场道路时遇到的问题,即如何以最小的成本连接所有农场。Prim算法被用于找到连接所有农场的最短总路径,博客提供了输入输出示例,并给出了算法的应用示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Description

Farmer John最近得到了一些新的农场,他想新修一些道路使得他的所有农场可以经过原有的或是新修的道路互达(也就是说,从任一个农场都可以经过一些首尾相连道路到达剩下的所有农场)。有些农场之间原本就有道路相连。 所有N(1 <= N <= 1,000)个农场(用1..N顺次编号)在地图上都表示为坐标为(X_i, Y_i)的点(0 <= X_i <= 1,000,000;0 <= Y_i <= 1,000,000),两个农场间道路的长度自然就是代表它们的点之间的距离。现在Farmer John也告诉了你农场间原有的M(1 <= M <= 1,000)条路分别连接了哪两个农场,他希望你计算一下,为了使得所有农场连通,他所需建造道路的最小总长是多少。

Input
* 第1行: 2个用空格隔开的整数:N 和 M
* 第2..N+1行: 第i+1行为2个用空格隔开的整数:X_i、Y_i * 第N+2..N+M+2行: 每行用2个以空格隔开的整数i、j描述了一条已有的道路, 这条道路连接了农场i和农场j

Output
* 第1行: 输出使所有农场连通所需建设道路的最小总长,保留2位小数,不必做 任何额外的取整操作。为了避免精度误差,计算农场间距离及答案时 请使用64位实型变量

Sample Input
4 1
1 1
3 1
2 3
4 3
1 4

输入说明:
FJ一共有4个坐标分别为(1,1),(3,1),(2,3),(4,3)的农场。农场1和农场4之间原本就有道路相连。

Sample Output
4.00

输出说明:
FJ选择在农场1和农场2间建一条长度为2.00的道路,在农场3和农场4间建一条长度为2.00的道路。这样,所建道路的总长为4.00,并且这是所有方案中道路总长最小的一种。

HINT

Source
Silver

题解
简单朴素的prim算法,具体过程请点这里

代码

#include <cstdio>
#include <algorithm>
#include <cmath>
using namespace std;

const int inf=1000000000;

double dist[1009][1009];
double low[1009];
int x[1009],y[1009],tr[1009];
int n,m,i,j,ans,xx,yy,mini;
double sum,minn;

double sqr(int a)
{
    return 1.0*a*a;
}

void makedist()//计算距离
{
    for (i=1;i<=n;i++)
    {
        for (j=1;j<=n;j++)
        {
            dist[i][j]=sqrt(sqr(x[i]-x[j])+sqr(y[i]-y[j]));
        }
    }
}

int prim()//prim算法
{
    tr[1]=1;
    for (i=1;i<=n;i++)
    {
        low[i]=inf;
    }
    for (i=2;i<=n;i++)
    {
        low[i]=dist[1][i];
    }
    mini=1;
    sum=0;
    for (i=1;i<=n-1;i++)
    {
        minn=inf;
        for (j=1;j<=n;j++)
        {
            if ((low[j]<minn)&&(tr[j]==0))
            {
                minn=low[j];
                mini=j;
            }
        }
        tr[mini]=1;
        sum+=minn;
        for (j=1;j<=n;j++)
        {
            if ((tr[j]==0)&&(low[j]>dist[mini][j]))
            {
                low[j]=dist[mini][j];
            }
        }
    }
    printf("%.2lf",sum);
    return 0;
}

int main()
{
    scanf("%d%d",&n,&m);
    for (i=1;i<=n;i++)
    {
        scanf("%d%d",&x[i],&y[i]);
    }
    makedist();
    for (i=1;i<=m;i++)
    {
        scanf("%d%d",&xx,&yy);
        dist[xx][yy]=dist[yy][xx]=0;
    }
    ans=prim();
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值