http://172.20.6.3/Problem_Show.asp?id=1636
复习了prim,分数规划大概就是把一个求最小值或最大值的分式移项变成一个可二分求解的式子。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<cmath> 6 #include<cstdlib> 7 using namespace std; 8 const int maxn=1100; 9 const double eps=0.0001; 10 int n; 11 long long c[maxn][3]={}; 12 double e[maxn][maxn]={}; 13 double t[maxn][maxn]={}; 14 double w[maxn][maxn]={},k[maxn]={}; 15 bool vis[maxn]={}; 16 inline long long mabs(long long x){ return x>0?x:-x; } 17 inline long long sqr(long long x){ return x*x; } 18 bool ke(double v){ 19 memset(vis,0,sizeof(vis)); 20 for(int i=1;i<=n;i++){ 21 for(int j=i;j<=n;j++){ 22 w[i][j]=w[j][i]=t[i][j]-v*e[i][j]; 23 } 24 }vis[1]=1;double fla=0; 25 for(int i=1;i<=n;i++){ 26 k[i]=w[1][i]; 27 } 28 for(int i=1;i<n;++i){ 29 int u=-1; 30 for(int j=1;j<=n;++j){ 31 if(!vis[j]) 32 if(u==-1||k[j]<k[u])u=j; 33 } 34 fla+=k[u];vis[u]=1; 35 for(int j=1;j<=n;++j){ 36 if(!vis[j]) 37 if(w[u][j]<k[j])k[j]=w[u][j]; 38 } 39 } 40 return fla<=0; 41 } 42 double doit(double l,double r){ 43 while(r-l>eps){ 44 double mid=(l+r)/2; 45 if(ke(mid))r=mid; 46 else l=mid+eps; 47 } 48 return l; 49 } 50 int main(){ 51 //freopen("wtf.in","r",stdin); 52 scanf("%d",&n); 53 for(int i=1;i<=n;i++){ 54 scanf("%lld%lld%lld",&c[i][0],&c[i][1],&c[i][2]); 55 } 56 for(int i=1;i<=n;i++){ 57 for(int j=i;j<=n;j++){ 58 e[i][j]=sqrt((double)(sqr(c[i][0]-c[j][0])+sqr(c[i][1]-c[j][1]))); 59 t[i][j]=(double)mabs(c[i][2]-c[j][2]); 60 e[j][i]=e[i][j];t[j][i]=t[i][j]; 61 } 62 }printf("%.3f",doit(1,100)); 63 return 0; 64 }