算法刷题记录(Day 42)

这篇博客详细介绍了如何解决POJ2728(DesertKing)问题,这是一道关于0/1分划之最小比率生成树的算法题。博主通过二分搜索结合Prim算法来寻找最小生成树,从而求解题目中费用与长度比值的最小值。在解题过程中,博主发现并修复了导致AC失败的细节错误,即未注释掉不必要的输出语句。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Desert King(poj 2728)

原题链接

题目类型:0/1分划之最小比率生成树

解题思路:假设费用之和为A,长度之和为B,题意为求解A/B的最小值。
采用二分的思路,假设某结果为ans,
若存在一组解,使得A-Bans<0,即代表最小值比ans小,因此移动上界。为了找到sigma(ai-bians)<0的一组解,采用贪心的思想,去找较小的一组ai-bians,若该组都无法使得A-Bans小于0,则代表不存在该组解。
那么如何去找到较小的一组ai-bians呢?基于该题要求生成的是一棵以capital village为根的树,因此将ai-bians设置为边值,那么问题也就转化为求解最小生成树。

那么是使用kruskal还是prim呢?n的最大值为1000,即点数n为1000,边数m为5*10^5
,prim算法的复杂度为O(n2),kruskal的时间复杂度为O(m logm),因此选用prim算法。

那么,初始的L和R值应该如何设置呢?设置L为0,寻找ai的最大值,bi的最小值,设置其比值为R的初始值

kruskal时间复杂度分析


#include<iostream>
#include<cmath>

using namespace std;
#define NMAX 1003
int N;
double x[NMAX], y[NMAX], z[NMAX];
//double map[NMAX][NMAX];
double length(int i, int j,double R) {
	return fabs(z[i] - z[j]) - R * sqrt((x[i] - x[j]) * (x[i] - x[j]) + (y[i] - y[j]) * (y[i] - y[j]));
}
int check(double R) {
	//double map[NMAX][NMAX];
	double res = 0;
	int vis[NMAX];
	memset(vis, 0, sizeof(vis));
	double dis[NMAX];
	for (int i = 0; i < N; i++) dis[i] = length(0,i,R);
	vis[0] = 1;
	for (int k = 1; k < N ; k++) {
		//找最小的边
		double MIN = 10000000;
		int mlot = 0;
		for (int i = 0; i < N; i++) {
			if (!vis[i] && dis[i] < MIN) {
				MIN = dis[i], mlot = i;
			}
		}
		vis[mlot] = 1;
		res += MIN;
		//更新
		for (int i = 0; i < N; i++) {
			if (!vis[i] && length(mlot, i, R) < dis[i] ) dis[i] = length(mlot, i, R);
		}
	}
	//printf("%.3lf\n", res);
	if (res < 0) return 1;
	else return 0;
}
int main() {
	while (1) {
		//cin >> N;
		scanf_s("%d", &N);
		if (!N) break;
		//double zmax = 0, ymin = 1e4 + 4;
		for (int i = 0; i < N; i++) {
			//cin >> x[i] >> y[i] >> z[i];
			scanf_s("%lf %lf %lf", &x[i], &y[i], &z[i]);
			//if (z[i] > zmax) zmax = x[i];
			//if (y[i] < ymin || x[]) ymin = y[i];
		}
		double L = 0, R = 100.0, M;
		while (R - L > 1e-7) {
			M = (R + L) / 2;
			if (check(M)) R = M;
			else L = M;
		}
		printf("%.3lf\n", R);
	}
}

tip: AC不了的原因竟然是没有注释掉printf(“%.3lf\n”, res); 我真的是服了我自己了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值