uva 10012(暴力求解)

题意:给出n个圆,和每个圆的半径,求出如果把这些圆放到一个矩形内,且每个圆都接触矩形的底边,求出矩形的最短长度。

题解:根据题目意思,如果矩形的长度要最短,说明圆都很紧密的靠在一起,所以每个圆至少和一个圆相切,相切并在同一平面上的两个圆心的水平距离公式是sqrt((r1 + r2) ^2 - (r1 - r2) ^2)。开始先将n个圆的半径全排列以确定摆放顺序,然后计算每个序列的矩形长度。这里运用一个pos[N]数组记录每个圆的圆心到矩形左边的距离,然后根据圆的半径和摆放方式更新,最后比较每次得到的矩形长度,较小的保留。

#include <stdio.h>
#include <math.h>
#include <algorithm>
using namespace std;
const int N = 10;
const double INF = 9999999999999;

double r[N], minn;
double pos[N];//记录每个点到矩形左边的距离
int n;

double cal(int i, int j) {//计算圆心的水平距离
	double a = r[i] + r[j];
	double b = r[i] - r[j];
	return sqrt(a * a - b * b);
}

void judge() {
	pos[0] = r[0];
	for (int i = 0; i < n - 1; i++) {
		pos[i + 1] = pos[i] + cal(i + 1, i);//更新每个圆的当前距离
		if (pos[i + 1] < r[i + 1])
			pos[i + 1] = r[i + 1];//如果当前距离加上两圆心水平距离小于下一个圆的半径,就将下一个圆的到矩形左边的距离置为它的半径
		for (int j = 0; j < i + 1; j++)
			if (pos[i + 1] - pos[j] < cal(i + 1, j))
				pos[i + 1] = pos[j] + cal(i + 1, j);//如果两个大圆之间有一个半径非常小的圆,这个圆在更新当前距离的时候和两个大圆都相切,但是明显这样的话两个大圆就重叠了,所以让后面大圆的当前距离更新为加上与左边大圆相切后的距离
	}
	double temp = pos[n - 1];
	for (int i = 0; i < n; i++) //有可能存在一个很大的圆的当前距离加自己的半径大于最后一个圆的当前距离,就替换掉,否则加上最后一个圆的半径
		if (pos[i] + r[i] > temp)
			temp = pos[i] + r[i];
	if (temp < minn)
		minn = temp;
}

int main() {
	int t;
	scanf("%d", &t);
	while (t--) {
		minn = INF;
		scanf("%d", &n);
		for (int i = 0; i < n; i++) 
			scanf("%lf", &r[i]);
		sort(r, r + n);
		do {
			judge();
		} while(next_permutation(r, r + n));//下一个排列
		printf("%.3lf\n", minn);
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值