思路:最小生成树+kruskal
1 题目要求的找到n个商店组成n-1条边,并且要求耐克和苹果商店肯定要相连,求最短长度
2 很明显的最小生成树的模板题,由于要求耐克和苹果的商店要在一起那么就要把这两个商店编号合并到同一个集合,然后在利用kruskal计算。
代码:
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> using namespace std; #define MAXN 10010 #define N 55 double ans; int n , P , Q , pos; int father[MAXN]; int rank[MAXN]; struct Point{ int x; int y; }p[N]; struct Edge{ int x; int y; double value; }e[MAXN]; bool cmp(Edge e1 , Edge e2){ return e1.value < e2.value; } void init(){ pos = 0; for(int i = 1 ; i <= n ; i++){ for(int j = i+1 ; j <= n ; j++){ double tmpx = (p[i].x-p[j].x)*(p[i].x-p[j].x); double tmpy = (p[i].y-p[j].y)*(p[i].y-p[j].y); double tmp = sqrt(tmpx+tmpy); e[pos].x = i , e[pos].y = j; e[pos++].value = tmp; if(i == P && j == Q) ans = tmp; } } } void init_Set(){ for(int i = 0 ; i <= n ; i++){ father[i]= i; rank[i] = 0; } } int find_Set(int x){ if(father[x] != x) father[x] = find_Set(father[x]); return father[x]; } void union_Set(int x , int y){ if(rank[x] > rank[y]) father[y] = x; else{ if(rank[x] == rank[y]) rank[y]++; father[x] = y; } } void kruskal(){ init(); init_Set(); sort(e , e+pos , cmp); union_Set(P , Q); for(int i = 0 ; i < pos ; i++){ int root_x = find_Set(e[i].x); int root_y = find_Set(e[i].y); if(root_x != root_y){ ans += e[i].value; union_Set(root_x , root_y); } } } int main(){ while(scanf("%d" , &n) && n){ scanf("%d%d" , &P , &Q); if(P > Q) swap(P , Q); for(int i = 1 ; i <= n ; i++) scanf("%d%d" , &p[i].x , &p[i].y); kruskal(); printf("%0.2lf\n" , ans); } return 0; }