(有任何问题欢迎留言或私聊 && 欢迎交流讨论哦
目录
题意:传送门
原题目描述在最下面。
三维坐标下给你n个点,两个点之间的距离是平面欧式距离,两个点之间的花费是高度差。
求一颗生成树使得费用和距离的比值最小。
思路:
不是很懂唉,什么01分数规划。
这题就是二分比率m, m=cost/dis m = c o s t / d i s 。 ∑(cost−dis×m) ∑ ( c o s t − d i s × m ) 大于0表示比率m还可以更大,反之m要变小才行。
二分跑了
1641ms
1641
m
s
.
AC代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<assert.h>
#include<bitset>
#include<cmath>
#define lson rt<<1
#define rson rt<<1|1
#define lowbit(x) (x)&(-(x))
#define all(x) (x).begin(),(x).end()
using namespace std;
typedef long long LL;
const int INF = 0x3f3f3f3f;
const double eps = 1e-7;
const int N = (int)1e3 +107;
int n;
double dis[N], ar[N][N];
int vis[N];
struct lp{
int x,y,h;
}cw[N*N];
double len(int x1,int y1,int x2,int y2){
return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)*1.0);
}
bool prim(double m){
for(int i=1;i<=n;++i){
dis[i] = INF;
vis[i] = 0;
}
double res = 0;
dis[1] = 0;
for(int t=1;t;++t){
double mmax=INF;
int p = -1;
for(int i=1;i<=n;++i){
if(vis[i]==0&&mmax>dis[i]){
mmax = dis[i];
p = i;
}
}
if(p==-1)break;
res+=mmax;
vis[p]=1;
for(int i=1;i<=n;++i){
if(vis[i]==0&&dis[i]>fabs(cw[i].h*1.0-cw[p].h) - ar[p][i]*m){
dis[i] = fabs(cw[i].h*1.0-cw[p].h) - ar[p][i]*m;
}
}
}
return res>=0;
}
int main(){
while(~scanf("%d", &n)&&n){
for(int i=1;i<=n;++i){
scanf("%d%d%d",&cw[i].x,&cw[i].y,&cw[i].h);
}
for(int i=1;i<=n;++i){
for(int j=i;j<=n;++j){
ar[i][j]=ar[j][i]=len(cw[i].x,cw[i].y,cw[j].x,cw[j].y);
}
}
double l=0,r=200,mid;
while(r-l>eps){
mid=(l+r)/2;
if(prim(mid))l=mid;
else r=mid;
}
printf("%.3f\n", r);
}
return 0;
}