ZOJ 1203 Swordfish(最小生成树Prim)
复习。
借图= =
n个点,给出两两点之间的距离,求最小生成树的边长度之和。
稠密图,用prim。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <iostream>
2 #include <cmath>
3 #include <cstring>
4 #include <iomanip>
5 using namespace std;
6
7 const double maxd = 1000001;
8 const int N = 105;
9
10 double x[N], y[N];
11 double map1[N][N], dis[N];
12 int vis[N];
13
14 double cal(int i, int j)
15 {
16 double ret = (y[i] - y[j]) * (y[i] - y[j]) + (x[i] - x[j]) * (x[i] - x[j]);
17 return sqrt(ret);
18 }
19
20 void input(int n)
21 {
22 for(int i=1; i<=n; i++)
23 cin >> x[i] >> y[i];
24 for(int i=1; i<=n; i++)
25 {
26 map1[i][i] = maxd;
27 for(int j=i+1; j<=n; j++)
28 map1[i][j] = map1[j][i] = cal(i,j);
29 }
30 }
31
32 /*
33 *代码思路:已一个点为起点,找n-1次,每次添加一个点进入结果集
34 *dis[i]维护结果集与i点的最短距离
35 *vis[i]代表点i是否已加入结果集
36 *
37 */
38 double prim(int n)
39 {
40 double ret = 0;
41 int cur = 1;
42 for(int i=1; i<=n; i++) dis[i] = maxd;
43 memset(vis, 0, sizeof(vis));
44 dis[cur] = 0; vis[cur] = 1;
45 //找n-1轮
46 for(int i=1; i<n; i++)
47 {
48 //枚举上一次加入的点与各个点的距离,更新最小距离dis[i]
49 for(int j=1; j<=n; j++)
50 {
51 if(vis[j]==0 && dis[j]>map1[cur][j])
52 dis[j] = map1[cur][j];
53 }
54 //选出最短的边,把该边连接的点加入结果集
55 double mind = maxd;
56 for(int j=1; j<=n; j++)
57 {
58 if(vis[j]==0 && dis[j]<mind)
59 {
60 mind = dis[j];
61 cur = j;
62 }
63 }
64 vis[cur] = 1;
65 ret += mind;
66 //cout << i << ": " << mind << endl;
67 }
68 return ret;
69 }
70
71 int main()
72 {
73 int Case = 1, n;
74 while(cin >> n)
75 {
76 if(n==0) break;
77 input(n);
78 double ans = prim(n);
79
80 if(Case>1) cout << endl;
81 cout << "Case #" << Case++ << ":" << endl;
82 cout << "The minimal distance is: ";
83 cout << setiosflags(ios::fixed) << setprecision(2) << ans << endl;
84 }
85 return 0;
86 }
2 #include <cmath>
3 #include <cstring>
4 #include <iomanip>
5 using namespace std;
6
7 const double maxd = 1000001;
8 const int N = 105;
9
10 double x[N], y[N];
11 double map1[N][N], dis[N];
12 int vis[N];
13
14 double cal(int i, int j)
15 {
16 double ret = (y[i] - y[j]) * (y[i] - y[j]) + (x[i] - x[j]) * (x[i] - x[j]);
17 return sqrt(ret);
18 }
19
20 void input(int n)
21 {
22 for(int i=1; i<=n; i++)
23 cin >> x[i] >> y[i];
24 for(int i=1; i<=n; i++)
25 {
26 map1[i][i] = maxd;
27 for(int j=i+1; j<=n; j++)
28 map1[i][j] = map1[j][i] = cal(i,j);
29 }
30 }
31
32 /*
33 *代码思路:已一个点为起点,找n-1次,每次添加一个点进入结果集
34 *dis[i]维护结果集与i点的最短距离
35 *vis[i]代表点i是否已加入结果集
36 *
37 */
38 double prim(int n)
39 {
40 double ret = 0;
41 int cur = 1;
42 for(int i=1; i<=n; i++) dis[i] = maxd;
43 memset(vis, 0, sizeof(vis));
44 dis[cur] = 0; vis[cur] = 1;
45 //找n-1轮
46 for(int i=1; i<n; i++)
47 {
48 //枚举上一次加入的点与各个点的距离,更新最小距离dis[i]
49 for(int j=1; j<=n; j++)
50 {
51 if(vis[j]==0 && dis[j]>map1[cur][j])
52 dis[j] = map1[cur][j];
53 }
54 //选出最短的边,把该边连接的点加入结果集
55 double mind = maxd;
56 for(int j=1; j<=n; j++)
57 {
58 if(vis[j]==0 && dis[j]<mind)
59 {
60 mind = dis[j];
61 cur = j;
62 }
63 }
64 vis[cur] = 1;
65 ret += mind;
66 //cout << i << ": " << mind << endl;
67 }
68 return ret;
69 }
70
71 int main()
72 {
73 int Case = 1, n;
74 while(cin >> n)
75 {
76 if(n==0) break;
77 input(n);
78 double ans = prim(n);
79
80 if(Case>1) cout << endl;
81 cout << "Case #" << Case++ << ":" << endl;
82 cout << "The minimal distance is: ";
83 cout << setiosflags(ios::fixed) << setprecision(2) << ans << endl;
84 }
85 return 0;
86 }
注意算法思想与代码思路。。