poj 3625

题目概述

有N个地点,编号1到N,坐标x,y,要修路使得所有地点之间连通,有M条已经存在的路,问最少还需修多长的路

时限

1000ms/3000ms

输入

第一行两个整数N,M,其后N行,每行两个整数x,y,其后M行,每行两个整数代表这两点之间已经有路

限制

1<=N,M<=1000;0<=x,y<=1e6

输出

一个保留两位小数的浮点数,为所求修路长度

样例输入

4 1
1 1
3 1
2 3
4 3
1 4

样例输出

4.00

讨论

图论,最小生成树,prim算法,和普通的最小生成树其实没什么差别,算出两点间距离,将已存在路连接的点距离清零,然后固定算法即可
实现上需要注意,虽然给的坐标是整数,但如果直接算距离,其一,上溢,这点数据范围和原题都说的很确切,其二,poj不认识c++11的整型重载sqrt,会得到CE,所以读入时直接作为浮点数就好了
其实用long long也能做,但即便只在最后算一次sqrt速度也远不如double,而且还得考虑INF的大小

题解状态

8064K,63MS,C++,1173B

题解代码

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<cmath>
using namespace std;
#define INF 0x3f3f3f3f
#define MAXN 1003
#define memset0(a) memset(a,0,sizeof(a))

int N, M;//点总数 已存在路总数
double x[MAXN], y[MAXN];//点的坐标
double graph[MAXN][MAXN], dis[MAXN];//邻接矩阵 树上边长
bool mk[MAXN];//已在树上标记
double fun()
{
    for (int p = 1; p <= N; p++)
        scanf("%lf%lf", &x[p], &y[p]);//input
    for (int p = 1; p <= N; p++)
        for (int i = p + 1; i <= N; i++)
            graph[p][i] = graph[i][p] = sqrt((x[p] - x[i])*(x[p] - x[i]) + (y[p] - y[i])*(y[p] - y[i]));//算出两点间距离
    for (int p = 0; p < M; p++) {
        int a, b;
        scanf("%d%d", &a, &b);//input
        graph[a][b] = graph[b][a] = 0;//已存在的直接归零
    }
    double sum = 0;//下面就是prim的主体了
    mk[1] = 1;
    for (int p = 1; p <= N; p++)
        dis[p] = graph[1][p];
    for (int p = 1; p < N; p++) {
        double least = INF;
        int pos;
        for (int p = 1; p <= N; p++) {
            if (!mk[p] && least>dis[p]) {
                least = dis[p];
                pos = p;
            }
        }
        mk[pos] = 1;
        sum += least;
        for (int p = 1; p <= N; p++)
            if (!mk[p] && dis[p] > graph[pos][p])
                dis[p] = graph[pos][p];
    }
    return sum;
}
int main(void)
{
    //freopen("vs_cin.txt", "r", stdin);
    //freopen("vs_cout.txt", "w", stdout);

    scanf("%d%d", &N, &M);//input
    printf("%.2lf\n", fun());//output
}

EOF

展开阅读全文
©️2020 CSDN 皮肤主题: 编程工作室 设计师: CSDN官方博客 返回首页
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值