348. 沙漠之王

题目链接

348. 沙漠之王

大卫大帝刚刚建立了一个沙漠帝国,为了赢得他的人民的尊重,他决定在全国各地建立渠道,为每个村庄提供水源。

与首都相连的村庄将得到水资源的浇灌。

他希望构建的渠道可以实现单位长度的平均成本降至最低。

换句话说,渠道的总成本和总长度的比值能够达到最小。

他只希望建立必要的渠道,为所有的村庄提供水资源,这意味着每个村庄都有且仅有一条路径连接至首都。

他的工程师对所有村庄的地理位置和高度都做了调查,发现所有渠道必须直接在两个村庄之间水平建造。

由于任意两个村庄的高度均不同,所以每个渠道都需要安装一个垂直的升降机,从而使得水能够上升或下降。

建设渠道的成本只跟升降机的高度有关,换句话说只和渠道连接的两个村庄的高度差有关。

需注意,所有村庄(包括首都)的高度都不同,不同渠道之间不能共享升降机。

输入格式

输入包含多组测试数据。

每组测试数据第一行包含整数 \(N\),表示村庄(包括首都)的总数目。

接下来 \(N\) 行,每行包含三个整数 \(x,y,z\),描述一个村庄的地理位置,\((x,y)\) 为该村庄的位置坐标,\(z\) 为该村庄的地理高度。

第一个被描述的村庄即为首都。

当输入一行为 \(0\) 时,表示输入终止。

输出格式

每组数据输出一个结果,每个结果占一行。

结果为一个保留三位小数的实数,表示渠道的总成本和总长度的比值的最小值。

数据范围

\(2≤N≤1000,\)
\(0≤x,y<10000,\)
\(0≤z≤10000000\)

输入样例:

4
0 0 0
0 1 1
1 1 2
1 0 3
0

输出样例:

1.000

解题思路

01分数规划,最小生成树

求01分数规划的最小值,即 \(\frac{a_1+a_2+\dots+a_{n-1}}{b_1+b_2+\dots+b_{n-1}}\) 的最小值,设其为 \(L\),假设存在 \(x_i\) 使得 \(\sum a_i-Lb_i\geq 0\),即 \(L\leq \sum \frac{a_i}{b_i}x_i\),说明 \(L\) 太小,反之 \(L\) 太大,显然后者出现的情况出现的越多越好,即 \(\sum a_i-Lb_i\) 越小越好,即转化为求最小生成树

  • 时间复杂度:\(O(n^2log(2e9))\)

代码

// Problem: 沙漠之王
// Contest: AcWing
// URL: https://www.acwing.com/problem/content/description/350/
// Memory Limit: 64 MB
// Time Limit: 2000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

// %%%Skyqwq
#include <bits/stdc++.h>
 
//#define int long long
#define help {cin.tie(NULL); cout.tie(NULL);}
#define pb push_back
#define fi first
#define se second
#define mkp make_pair
#define eps 1e-6
using namespace std;
 
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
 
template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; }
template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; }
 
template <typename T> void inline read(T &x) {
    int f = 1; x = 0; char s = getchar();
    while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); }
    while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar();
    x *= f;
}

const int N=1005;
int n;
double d[N];
bool v[N];
struct A
{
	double x,y,h;
}a[N];
double dist(A &a,A &b)
{
	return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
bool prime(double l)
{
	double res=0;
	fill(d,d+1+n,1e18);
	fill(v,v+1+n,0);
	d[1]=0;
	for(int i=1;i<=n;i++)
	{
		int x=0;
		for(int j=1;j<=n;j++)
			if(!v[j]&&(x==0||d[x]>d[j]))x=j;
		res+=d[x];
		v[x]=true;
		for(int j=1;j<=n;j++)
			if(!v[j]&&d[j]>fabs(a[x].h-a[j].h)-l*dist(a[x],a[j]))
				d[j]=fabs(a[x].h-a[j].h)-l*dist(a[x],a[j]);
	}
	return res>=0;
}
int main()
{
	while(cin>>n,n)
	{
	    for(int i=1;i<=n;i++)cin>>a[i].x>>a[i].y>>a[i].h;
	    double l=0,r=2e9;
	    while(fabs(l-r)>eps)
	    {
	    	double mid=(l+r)/2;
	    	if(prime(mid))l=mid;
	    	else
	    		r=mid;
	    }
	    printf("%.3lf\n",l);
	}
    
    return 0;
}
posted @ 2022-03-15 21:15  zyy2001  阅读(131)  评论(0编辑  收藏  举报