(最優比率生成樹)POJ 2728 - Desert King

題意:算法

不少村子,村子有三維座標的屬性,如今要求一個生成樹,使得總高度和總寬度比率最小。ui

 

分析:spa

很經典的題型,能夠使用二分來作,這裏引用紅書上的【說明】。code

二分答案,假設最小的答案爲best,二分答案爲ans,那麼咱們將每條邊的邊權變爲wi-ui*ans,則:blog

ans<best時,求最小生成樹獲得的答案>0string

ans=best時,求最小生成樹獲得的答案=0it

ans>best時,求最小生成樹獲得的答案<0io

這裏使用prim算法check一下便可。class

還有一種算法是迭代法,就是初設一個值,將這個值代進去算,獲得更優的解,直至徹底收斂。引用

速度比二分快,具體須要看題。

 

代碼:

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 #include <cmath>
 5 
 6 using namespace std;
 7 
 8 #define eps (1e-6)
 9 const int inf=0x3f3f3f3f;
10 const int maxn=1010;
11 int n;
12 
13 double x[maxn];
14 double y[maxn];
15 double z[maxn];
16 double dist[maxn][maxn];
17 double high[maxn][maxn];
18 
19 int sgn(double x) {
20     return x < -eps ? -1 : x > eps ? 1 : 0;
21 }
22 
23 double lowc[maxn];
24 bool vis[maxn];
25 
26 double dis(double x1,double y1,double x2,double y2) {
27     return sqrt(pow(x1-x2,2)+pow(y1-y2,2));
28 }
29 
30 double check(double r) {
31     double ans=0;
32     memset(vis,false,sizeof(vis));
33     vis[0]=true;
34     for(int i=1; i<n; i++) {
35         lowc[i]=high[0][i]-dist[0][i]*r;
36     }
37     for(int i=1; i<n; i++) {
38         double minc=inf;
39         int p=-1;
40         for(int j=0; j<n; j++) {
41             if(!vis[j]&&lowc[j]<minc) {
42                 minc=lowc[j];
43                 p=j;
44             }
45         }
46         ans+=minc;
47         vis[p]=true;
48         for(int j=0; j<n; j++) {
49             double d = high[p][j]-dist[p][j]*r;
50             if(!vis[j]&&lowc[j]>d) {
51                 lowc[j]=d;
52             }
53         }
54     }
55     return ans;
56 }
57 
58 
59 int main() {
60     while(scanf("%d",&n)&&n) {
61         for(int i=0; i<n; i++) {
62             scanf("%lf%lf%lf",&x[i],&y[i],&z[i]);
63         }
64         for(int i=0; i<n; i++) {
65             for(int j=i+1; j<n; j++) {
66                 dist[i][j]=dist[j][i]=dis(x[i],y[i],x[j],y[j]);
67                 high[i][j]=high[j][i]=fabs(z[i]-z[j]);
68 //                printf("%f %f\n",dist[i][j],high[i][j]);
69             }
70         }
71         double left=0;
72         double right = 100;
73         while(sgn(left-right)<0) {
74             double mid = (left+right)/2;
75             double res = check(mid);
76 //            printf("%f %f\n",mid,res);
77             if(sgn(res)<0) {
78                 right=mid;
79             } else  if(sgn(res)>0) {
80                 left=mid;
81             } else {
82                 break;
83             }
84         }
85         printf("%.3f\n",(left+right)/2);
86     }
87 
88     return 0;
89 
90 }
相關文章
相關標籤/搜索