题意:
最优比率生成树,要求生成树中的所有边的花费与所有边的长度的比值最小
题解:
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 }