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 }

 

 

你可能感兴趣的:(poj)