UVA 10034 - Freckles

Q10034: Freckles

給你一些點的座標,把這些點用墨水畫直線連起來,使得所有的點最後都連在一起。你的任務是寫一個程式找出墨水畫出的長度最小是多少?

Input

輸入的第一列有一個整數,代表以下有幾組測試資料。

每組測試資料的第1列有一個整數n(0< n <= 100),代表點的個數。接下來有n列代表這n個點的座標,每列有2個實數。

輸入的第一列與第一組測試資料間空一列,各測試資料間亦空一列。請參考Sample Input

Output

對每一組測試資料輸出墨水畫出的長度最小是多少。測試資料間亦請空一列。

Sample Input
2

3
1.0 1.0
2.0 2.0
2.0 4.0

2
1.0 1.0
2.0 2.0

Sample Output
3.41

1.41

题目类型:  MST(最小生成树)

 

分析:

 最小生成树咯,基本是模板题,要说有一点不同就是每两个点间都可以有边,所以开始的时候init一下边。

关于最小生成树,kruskal算法,主要是用到并查集的思想。

但题目数据量比较小,所以我用了一种直观的方法表示集合。即对每个点,用一个对应的数来表示它所在的连通分量。只要一个数组就可以了。

这样对为什么要用并查集来写  kruskal也会有更深理解。

代码:

数组标记集合版,ac

 #include<iostream> #include<iomanip> //使用 setprecision(int) #include<cstring> #include<string> //string里包不包含cstring的? #include<cmath> #include<algorithm> using namespace std; #define MAXN 102 #define MAXM 5055 double w[MAXM]; //这题两两点间都有连线 int r[MAXM]; //要对r[]间接排序! int u[MAXM], v[MAXM]; double x[MAXN], y[MAXN]; int n; int ms[MAXN]; //集合标记 //为什么这种标记不行?因为难以实现合并集合的操作!效率不高. void merge(int a, int b) { for(int k=0; k<n; k++) if(ms[k] == b) ms[k] = a; } double mst() { int cnt=0; double ans=0; for(int i=0; i<n; i++) ms[i] = i; for(int i=0; i<n*(n-1)/2; i++) { int j = r[i]; if(ms[u[j]] == ms[v[j]]) continue; ans+=w[j]; merge(ms[u[j]], ms[v[j]]); cnt++; if(cnt==n-1) break; } return ans; } double dist(double x1, double y1, double x2, double y2) { double x = x1-x2; double y = y1-y2; return sqrt(x*x+y*y); } int cmp(const int a, const int b) { return w[a]<w[b]; } void read() { cin>>n; for(int i=0; i<n; i++) // i = 点的编号 cin>>x[i]>>y[i]; int e=0; //边序 for(int i=0; i<n; i++) // for(int j=0; j<n; j++) for(int j=i+1; j<n; j++) //强制 i<j ① { w[e] = dist(x[i], y[i], x[j], y[j]); u[e] = i; v[e] = j; r[e] = e; e++; } sort(r, r+e, cmp); //要掌握这种间接排序且利用sort的技术! } int main() { int t; cin>>t; for(int i=0; i<t; i++) { if(i) cout<<endl; read(); cout.setf(ios::fixed); cout<<setprecision(2)<<mst()<<endl; // printf("%.2lf/n", mst()); } }

 

你可能感兴趣的:(ios,算法,input,merge,output)