沙漠之王--最优比率生成树

ACwing 350

在这里插入图片描述

题目分析:

  • 预处理出村庄间的高度差 g [ i ] [ j ] g[i][j] g[i][j]和距离 f [ i ] [ j ] f[i][j] f[i][j]
  • 简化问题:有 n n n个点, m m m条边,边有两个属性: 成 本 a , 长 度 b 成本a,长度b ab,求
    在构成一棵树的情况下

m a x ( ∑ a [ i ] ∑ b [ i ] ) max(\frac{\sum{a[i]}}{\sum{b[i]}}) max(b[i]a[i])

  • 设答案为 a n s ans ans,则有 ∑ ( a [ i ] − b [ i ] ∗ a n s ) &lt; = 0 \sum{(a[i]-b[i]*ans)}&lt;=0 (a[i]b[i]ans)<=0
  • 二分 a n s ans ans,用 p r i m prim prim来判断

Code:

#include <bits/stdc++.h>
using namespace std;
#define re register
#define maxn 1010
#define eps 1e-6

int n,g[maxn][maxn];
double f[maxn][maxn],d[maxn];
bool vis[maxn];

struct node {
	int x,y,z;
}e[maxn];

inline void init_() {
	freopen("a.txt","r",stdin);
}

inline int read_() {
	int x=0,f=1;
	char c=getchar();
	while(c<'0'||c>'9') {
		if(c=='-') f=-1;
		c=getchar();
	}
	while(c>='0'&&c<='9') {
		x=(x<<1)+(x<<3)+c-'0';
		c=getchar();
	}
	return x*f;
}

inline void clean_() {
	
}

inline double dis_(double ax,double ay,double bx,double by) {
	return sqrt( (ax-bx) * (ax-bx) + (ay-by) * (ay-by) );
}

inline bool pd_(double x) {
	memset(vis,false,sizeof(vis));
	vis[1]=true;d[1]=0;
	for(re int i=2;i<=n;++i) {
		d[i]= (double) ( (double) g[1][i]) - f[1][i]*x;
	}
	double sum=0,mind;
	int u=-1;
	for(re int i=2;i<=n;++i) {
		mind=1e7;
		for(re int k=1;k<=n;++k) {
			if(!vis[k]&&d[k]<mind) {
				mind=d[k];
				u=k;
			}
		}
		if(u==-1) break;
		vis[u]=true;sum+=mind;
		for(re int j=1;j<=n;++j) {
			if(!vis[j]) d[j]=min(d[j],( (double) g[u][j])-f[u][j]*x);
 		}
	}
	if(sum>=0) return true;
	else return false;
}

void readda_() {
	while(scanf("%d",&n)!=EOF) {
		if(!n) return;
		clean_();
		for(re int i=1;i<=n;++i) {
			e[i].x=read_();e[i].y=read_();e[i].z=read_();
		}
		for(int i=1;i<=n;++i) {
			for(int j=i+1;j<=n;++j) {
				f[i][j]=f[j][i]=dis_( (double) e[i].x, (double) e[i].y, (double) e[j].x, (double) e[j].y);
				g[i][j]=g[j][i]=abs(e[i].z-e[j].z);
			}
		}
		double l=0,r=100,ans,mid;
		while(r-l>eps) {
			mid=(l+r)/2;
			if(pd_(mid)) {
				ans=mid;
				l=mid;
			}
			else r=mid;
		}
		printf("%.3lf\n",ans);
	}
}

int main() {
	init_();
	readda_();
	return 0;
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值