POJ 2728 01分数规划

题意:
最优比率生成树,要求生成树中的所有边的花费与所有边的长度的比值最小

 

题解:

01分数规划,详见http://www.cnblogs.com/proverbs/archive/2013/01/09/2853725.html

网上都是写的最小生成树,其实最大生成树也可以,其实写什么都一样,关键是根据公式的不等号方向判断~

 

最小生成树:

View Code
 1 #include <iostream>
 2 #include <cstdlib>
 3 #include <cstring>
 4 #include <cstdio>
 5 #include <algorithm>
 6 #include <cmath>
 7 
 8 #define N 1100
 9 const double INF=99999999.0;
10 
11 using namespace std;
12 
13 double sx[N],sy[N],sz[N],cost[N][N],map[N][N],dis[N];
14 double l,r,mid;
15 bool vis[N];
16 int n;
17 
18 inline double getdis(int a,int b)
19 {
20     return sqrt((sx[a]-sx[b])*(sx[a]-sx[b])+(sy[a]-sy[b])*(sy[a]-sy[b]));
21 }
22 
23 inline void read()
24 {
25     for(int i=1;i<=n;i++) scanf("%lf%lf%lf",&sx[i],&sy[i],&sz[i]);
26     for(int i=1;i<=n;i++)
27         for(int j=i+1;j<=n;j++)
28         {
29             map[i][j]=map[j][i]=getdis(i,j);
30             cost[i][j]=cost[j][i]=abs(sz[i]-sz[j]);
31         }
32 }
33 
34 inline bool check()//最小生成树 
35 {
36     for(int i=1;i<=n;i++) dis[i]=INF;
37     dis[1]=0.0;
38     memset(vis,false,sizeof vis);
39     double slen=0.0,mindis;
40     for(int j=1,k;j<=n;j++)
41     {
42         mindis=INF;
43         for(int i=1;i<=n;i++)
44             if(!vis[i]&&mindis>dis[i]) mindis=dis[i],k=i;
45         vis[k]=true; slen+=mindis;
46         for(int i=1;i<=n;i++)
47             if(!vis[i]&&cost[k][i]-mid*map[k][i]<dis[i]) dis[i]=cost[k][i]-mid*map[k][i];
48     }
49     if(slen>=0) return true;
50     return false;
51 }
52 
53 inline void go()
54 {
55     l=0.0,r=1010.0;
56     while(r-l>=1e-8)
57     {
58         mid=(l+r)/2.0;
59         if(check()) l=mid;
60         else r=mid;
61     }
62     printf("%.3lf\n",mid);
63 }
64 
65 int main()
66 {
67     while(scanf("%d",&n),n) read(),go();
68     return 0;
69 }

 

最大生成树:

View Code
 1 #include <iostream>
 2 #include <cstdlib>
 3 #include <cstring>
 4 #include <cstdio>
 5 #include <algorithm>
 6 #include <cmath>
 7 
 8 #define N 1100
 9 const double INF=99999999.0;
10 
11 using namespace std;
12 
13 double sx[N],sy[N],sz[N],cost[N][N],map[N][N],dis[N];
14 double l,r,mid;
15 bool vis[N];
16 int n;
17 
18 inline double getdis(int a,int b)
19 {
20     return sqrt((sx[a]-sx[b])*(sx[a]-sx[b])+(sy[a]-sy[b])*(sy[a]-sy[b]));
21 }
22 
23 inline void read()
24 {
25     for(int i=1;i<=n;i++) scanf("%lf%lf%lf",&sx[i],&sy[i],&sz[i]);
26     for(int i=1;i<=n;i++)
27         for(int j=i+1;j<=n;j++)
28         {
29             map[i][j]=map[j][i]=getdis(i,j);
30             cost[i][j]=cost[j][i]=abs(sz[i]-sz[j]);
31         }
32 }
33 
34 inline bool check()//最大生成树 
35 {
36     for(int i=1;i<=n;i++) dis[i]=-INF;
37     dis[1]=0.0;
38     memset(vis,false,sizeof vis);
39     double slen=0.0,maxdis;
40     for(int j=1,k;j<=n;j++)
41     {
42         maxdis=-INF;
43         for(int i=1;i<=n;i++)
44             if(!vis[i]&&maxdis<dis[i]) maxdis=dis[i],k=i;
45         vis[k]=true; slen+=maxdis;
46         for(int i=1;i<=n;i++)
47             if(!vis[i]&&mid*map[k][i]-cost[k][i]>dis[i]) dis[i]=mid*map[k][i]-cost[k][i];
48     }
49     if(slen>=0) return true;
50     return false;
51 }
52 
53 inline void go()
54 {
55     l=0.0,r=1010.0;
56     while(r-l>=1e-8)
57     {
58         mid=(l+r)/2.0;
59         if(check()) r=mid;
60         else l=mid;
61     }
62     printf("%.3lf\n",mid);
63 }
64 
65 int main()
66 {
67     while(scanf("%d",&n),n) read(),go();
68     return 0;
69 }

 

 

posted @ 2013-01-09 22:12  proverbs  阅读(222)  评论(0编辑  收藏  举报