链接:http://poj.org/problem?id=2728
题意:有几个点,不同的点有不同坐标和海拔,现在要讲几个点都连成一片,距离为两点之间的欧几里得距离,费用为两点之间的海拔高度,求最小的代价,代价定义为:r=(∑CiXi / ∑DiXi )。
分析:为了使 r 最大, 设计一个子问题---> 让 z = ∑(c[i] * x[i]) - l * ∑(d[i] * x[i]) = ∑(dd[i] * x[i]) 最大 (dd[i] = c[i] - l * d[i]) , 并记为z(l). 我们把z(l)看做以它为边权的最大生成树的总权值.
代码:
#include<cstdio>
#include<math.h>
#include<algorithm>
using namespace std;
const double eps=0.00001;
int n;
const int maxn=1005;
double e[maxn][maxn];
int pre[maxn];
double lowcost[maxn];
struct node{
int x,y,z;
}p[maxn];
double prime(double x){
double sum=0;
double len=0;
double cost=0;
for(int i=1;i<=n;i++){
pre[i]=1;
lowcost[i]=abs(p[1].z-p[i].z )-x*e[1][i];
}
pre[1]=-1;
for(int i=1;i<=n;i++){
int u=-1;
double minn=9999999;
for(int j=1;j<=n;j++){
if(pre[j]!=-1&&lowcost[j]<minn){
minn=lowcost[j];
u=j;
}
}
if(u!=-1){
cost+=abs(p[pre[u]].z-p[u].z );
len+=e[pre[u]][u];
pre[u]=-1;
sum+=lowcost[u];
for(int j=1;j<=n;j++){
double temp=abs(p[u].z-p[j].z )-x*e[u][j];
if(pre[j]!=-1&&temp<lowcost[j]){
lowcost[j]=temp;
pre[j]=u;
}
}
}
}
return sum;
}
double cal(int a,int b){
return sqrt(1.0 * (p[a].x - p[b].x) * (p[a].x - p[b].x) + 1.0 * (p[a].y - p[b].y) * (p[a].y - p[b].y));
}
int main(){
while(~scanf("%d",&n),n){
for(int i=1;i<=n;i++){
scanf("%d%d%d",&p[i].x,&p[i].y,&p[i].z);
}
for(int i=1;i<=n;i++){
for(int j=1;j<i;j++){
e[i][j]=e[j][i]=cal(i,j);
}
}
double l=0;
double r=100.0;
double mid;
while(r-l>eps){
mid=(l+r)*0.5;
if(prime(mid)>=0){
l=mid;
}else{
r=mid;
}
}
printf("%.3f\n",l);
}
}