poj 2349 最小生成树+第k小的边 细节太重要了

题目链接:http://poj.org/problem?id=2349

题目大意:有n个村庄要进行通信,现在只有两种通信设备,一种是卫星,通信距离可以任意远,另一种是电报,通信距离有一个上限,要增大上限的话就必须付出更大的代价,现在给你一些设备,n个卫星m个村庄的坐标,让你求可以是任意点直接或间接通信的电报上限距离d。

解题方法:本题是prim算法的经典变形,我们可以这样思考,有n的卫星,我们可以把村庄分成n个联通分量,一个联通分量发一个卫星,并且让每个连通分量内部各点间的最大距离不大于d,这样d即为最终的结果,现在的目标是求,各联通分量的上限的最大值,这里使用了一个定理:

如果去掉所有权大于d的边后最小生成树被分割成k个连通分支,图也被分割成k个连通分支;

这样目标变为求最小生成树的第k小的边,即为d;

View Code
 1 #include <iostream>
2 #include <cstdio>
3 #include <cmath>
4 #include <algorithm>
5 using namespace std;
6 const int INF=10000000.0;
7 struct ss{
8 double x,y;
9 }a[505];
10 double map[505][505];
11 double vv[505],dist[505];
12 int vist[505];
13 int n,m;
14 int cmp(double x,double y)
15 {
16 if(x>y)return 1;
17 return 0;
18 }
19 void prim()
20 {
21 int v,i,j,c=1;
22 double mi;
23 vist[1]=1;
24 for (i=2;i<=m;i++)
25 {
26 dist[i]=map[1][i];
27 }
28 dist[1]=0;
29 for (i=1;i<m;i++)
30 {
31 v=1;
32 mi=INF;
33 for (j=1;j<=m;j++)
34 if (!vist[j]&&dist[j]<mi)
35 {
36 mi=dist[j];
37 v=j;
38 }
39 vv[c++]=mi;
40 vist[v]=1;
41 for (j=1;j<=m;j++)
42 {
43 if(!vist[j]&&dist[j]>map[v][j])
44 dist[j]=map[v][j];
45 }
46 }
47 }
48 int main()
49 {
50 int i,j,k;
51 double kk;
52 scanf("%d",&k);
53 while (k--)
54 {
55 scanf("%d%d",&n,&m);
56 for (i=1;i<=m;i++)
57 {
58 dist[i]=INF;
59 scanf("%lf%lf",&a[i].x,&a[i].y);
60 }
61 for (i=1;i<=m;i++)
62 for(j=1;j<=m;j++)
63 {
64 if(i==j)map[i][j]=0.0;
65 else map[i][j]=INF;
66 }
67 memset(vv,0,sizeof(vv));
68 memset(vist,0,sizeof(vist));
69 for (i=1;i<m;i++)
70 for (j=i+1;j<=m;j++)
71 {
72 kk=sqrt((a[i].x-a[j].x)*(a[i].x-a[j].x)+(a[i].y-a[j].y)*(a[i].y-a[j].y));
73 map[i][j]=kk;
74 map[j][i]=map[i][j];
75 }
76 prim();
77 sort(vv+1,vv+m,cmp);
78 printf("%0.2lf\n",vv[n]);
79 }
80 return 0;
81 }
posted @ 2011-08-19 15:59  我们一直在努力  阅读(550)  评论(0编辑  收藏  举报