1. 程式人生 > >藍書(演算法競賽進階指南)刷題記錄——POJ2728 Desert King(最優比例生成樹)

藍書(演算法競賽進階指南)刷題記錄——POJ2728 Desert King(最優比例生成樹)

題目:POJ2728.

題目大意:給定一張無向完全圖,有邊權a和b,求出它的最優比例生成樹滿足a之和除以b之和最大.

我們發現這也是一個0-1分數規劃的模型.

根據0-1分數規劃的套路,我們二分一個比例mid,把這張圖的所有邊的邊權換成a_i-mid*b_i,然後跑一遍最大生成樹,判斷邊權和是否大於0即可.

程式碼如下:

#include<iostream>
#include<cstdio>
#include<cmath>
  using namespace std;
#define Abigail inline void
typedef long long LL;
const int N=1000;
const double eps=1e-6,INF=1e9;
int n;
double x[N+9],y[N+9],z[N+9];
double a[N+9][N+9],b[N+9][N+9],dis[N+9][N+9],d[N+9];
bool use[N+9];
double l,r,mid;
double distance(double x1,double y1,double x2,double y2){return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));}
double check(double mid){
  double sum=0;
  for (int i=0;i<=n;i++)
    use[i]=0,d[i]=INF;
  for (int i=1;i<=n;i++)
    for (int j=1;j<=n;j++)
      dis[i][j]=a[i][j]-mid*b[i][j];
  d[1]=0;
  for (int i=1;i<=n;i++){
    int v=0;
    for (int j=1;j<=n;j++)
      if (!use[j]&&d[v]>d[j]) v=j;
    sum+=d[v];use[v]=1;
    for (int j=1;j<=n;j++)
      if (!use[j]&&d[j]>dis[v][j]) d[j]=dis[v][j];
  }
  return sum;
}
Abigail into(){
  for (int i=1;i<=n;i++)
    scanf("%lf%lf%lf",&x[i],&y[i],&z[i]);
}
Abigail work(){
  for (int i=1;i<=n;i++)
    for (int j=1;j<=n;j++){
      a[i][j]=fabs(z[i]-z[j]);
      b[i][j]=distance(x[i],y[i],x[j],y[j]);
    }
  l=0;r=1e6;
  while (l+eps<r){
    mid=(l+r)/2;
    if (check(mid)>0) l=mid;
    else r=mid;
  }
}
Abigail outo(){
  printf("%.3f\n",mid);
}
int main(){
  while (~scanf("%d",&n)&&n){
    into();
    work();
    outo();
  }
  return 0;
}

一定要記住G++編譯器用%f輸出,C++編譯器用%lf輸出.

然後這道題還會卡常,eps和r之間的差距太大就會TLE.