蓝书(算法竞赛进阶指南)刷题记录——POJ2728 Desert King(最优比例生成树)

版权声明:转载请注明原出处啦QAQ(虽然应该也没人转载): https://blog.csdn.net/hzk_cpp/article/details/83143046

题目: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.

猜你喜欢

转载自blog.csdn.net/hzk_cpp/article/details/83143046
今日推荐