题目概述
有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