POJ2349(最小生成树)
题意:有两种不同的通信技术,有卫星通信的两个城市之间可以任意联络,但用无线电通信的城市只能和距离不超过D的城市联系。无线电的能力越高(即传输距离D越大),花费就越大。已知无线电的数目m,让求最小的D。
刚看完题目时,很迷茫,不知道该往哪去想,直到老师提醒我们用最小生成树解时,我才恍然大悟。这道题设计的真得很巧妙,如果不细心看题,及对最小生成树不熟练时,根本不知道从何下手。看来我练得还不到家,仍需继续努力。
思路:先求出每两个顶点之间的距离,(注意:是double类型的),然后用普里姆算法(Prim)求最小生成树。由于无线电的数目已给出m,需要把最小生成树分成m份,即删除m-1条边,得到m个连通分量。关键是删除哪些边呢,题目要求最小的D,故把构成最小生成树的边从大到小排序,删除前m-1条边,第m条边即所要求的最小D。其实只要思路清晰,很容易就把这道题A了。
代码如下:
View Code
1 #include<iostream>
2 #include<cmath>
3 #include<algorithm>
4 using namespace std;
5 #define Max 501
6 double map[Max][Max],d[Max];
7 int n,i,j;
8 struct{
9 int x,y;
10 }point[Max];
11 //记录从顶点集U到V-U的代价最小的边的辅助数组定义
12 struct{
13 int adjvex;
14 double lowcost;
15 }closedge[Max];
16 bool cmp(double a,double b)//从大到小偏序
17 {
18 return a>b;
19 }
20 //用普里姆算法从第k个顶点出发构造网G的最小生产树T
21 void prim(int k)
22 {
23 for(j=1;j<=n;j++)//辅助数组初始化
24 if(j!=k)
25 {
26 closedge[j].adjvex=k;
27 closedge[j].lowcost=map[k][j];
28 }
29 closedge[k].lowcost=0; //初始,U={u}
30 int l=0;
31 for(i=1;i<n;i++)//选择其余n-1个顶点
32 {
33 double min=1000000;
34 for(j=1;j<=n;j++)//求出T的下一个结点:第k顶点
35 if(closedge[j].lowcost!=0&&min>closedge[j].lowcost)
36 {
37 k=j;
38 min=closedge[j].lowcost;
39 }
40 closedge[k].lowcost=0; //第k顶点并入U集
41 d[l++]=map[k][closedge[k].adjvex]; //保存该边
42 for(j=1;j<=n;j++) //新顶点并入U后重新选择最小边
43 if(map[k][j]<closedge[j].lowcost)
44 {
45 closedge[j].adjvex=k;
46 closedge[j].lowcost=map[k][j];
47 }
48 }
49 }
50 int main()
51 {
52 int t,m;
53 cin>>t;
54 while(t--)
55 {
56 cin>>m>>n;
57 for(i=1;i<=n;i++)
58 cin>>point[i].x>>point[i].y;
59 for(i=1;i<=n;i++) //求出毎两个顶点之间的距离
60 for(j=1;j<i;j++)
61 map[i][j]=map[j][i]=sqrt((point[i].x-point[j].x)*(point[i].x
62 -point[j].x)+(point[i].y-point[j].y)*(point[i].y-point[j].y));
63 for(i=1;i<=n;i++)
64 map[i][i]=1000000;
65 prim(1);
66 sort(d,d+n-1,cmp); //把构成最小生成树的n-1条边从大到小排序
67 cout.setf(ios::fixed);//保留两位小数
68 cout.precision(2);
69 cout<<d[m-1]<<endl;//数组d从下标0开始存储,即第m条边
70 }
71 return 0;
72 }
2 #include<cmath>
3 #include<algorithm>
4 using namespace std;
5 #define Max 501
6 double map[Max][Max],d[Max];
7 int n,i,j;
8 struct{
9 int x,y;
10 }point[Max];
11 //记录从顶点集U到V-U的代价最小的边的辅助数组定义
12 struct{
13 int adjvex;
14 double lowcost;
15 }closedge[Max];
16 bool cmp(double a,double b)//从大到小偏序
17 {
18 return a>b;
19 }
20 //用普里姆算法从第k个顶点出发构造网G的最小生产树T
21 void prim(int k)
22 {
23 for(j=1;j<=n;j++)//辅助数组初始化
24 if(j!=k)
25 {
26 closedge[j].adjvex=k;
27 closedge[j].lowcost=map[k][j];
28 }
29 closedge[k].lowcost=0; //初始,U={u}
30 int l=0;
31 for(i=1;i<n;i++)//选择其余n-1个顶点
32 {
33 double min=1000000;
34 for(j=1;j<=n;j++)//求出T的下一个结点:第k顶点
35 if(closedge[j].lowcost!=0&&min>closedge[j].lowcost)
36 {
37 k=j;
38 min=closedge[j].lowcost;
39 }
40 closedge[k].lowcost=0; //第k顶点并入U集
41 d[l++]=map[k][closedge[k].adjvex]; //保存该边
42 for(j=1;j<=n;j++) //新顶点并入U后重新选择最小边
43 if(map[k][j]<closedge[j].lowcost)
44 {
45 closedge[j].adjvex=k;
46 closedge[j].lowcost=map[k][j];
47 }
48 }
49 }
50 int main()
51 {
52 int t,m;
53 cin>>t;
54 while(t--)
55 {
56 cin>>m>>n;
57 for(i=1;i<=n;i++)
58 cin>>point[i].x>>point[i].y;
59 for(i=1;i<=n;i++) //求出毎两个顶点之间的距离
60 for(j=1;j<i;j++)
61 map[i][j]=map[j][i]=sqrt((point[i].x-point[j].x)*(point[i].x
62 -point[j].x)+(point[i].y-point[j].y)*(point[i].y-point[j].y));
63 for(i=1;i<=n;i++)
64 map[i][i]=1000000;
65 prim(1);
66 sort(d,d+n-1,cmp); //把构成最小生成树的n-1条边从大到小排序
67 cout.setf(ios::fixed);//保留两位小数
68 cout.precision(2);
69 cout<<d[m-1]<<endl;//数组d从下标0开始存储,即第m条边
70 }
71 return 0;
72 }