NOJ1118玻璃球 【深蓝】——集合DP

玻璃球 【深蓝】

时间限制(普通/Java) : 10000 MS/ 30000 MS          运行内存限制 : 65536 KByte
总提交 : 47            测试通过 : 10 

比赛描述

玩过玻璃球游戏吗?sed同学小学没有毕业之前玩过,他常常用一个直径为d的圆柱管来装玻璃球,已知每个玻璃球是半径为 r1, r2, . . . , rn的球体,他当时一直有一个疑问:装这些玻璃球最少需要多长的圆柱管。现请你帮他解决这个问题。

假设玻璃球半径充分大,以至于管中不存在三个可以同时相互接触的玻璃球。给定这样的限制,表示玻璃球将总以这样的方式装入:他们的中心点位于含导管旋转轴的2维平面上。



输入

输入包含多个测试例。每个测试例包括两行。每个测试例的第一行包含一个整数n (1 ≤ n ≤ 15) ,表示sed持有玻璃球的数目,还有一个浮点值d (2.0 ≤ d ≤ 1000.0) ,表示管子直径。两值以空格隔开。每个测试例的第二行包含n个由空格分隔的浮点数r1 r2 . . . rn(1.0 ≤ ri ≤ d/2) ,为sed玻璃球的半径。一个空白行分隔所以输入测试例。一行“0 0” 表示输入结束,无需处理此例。

输出

对于每个输入测试例,打印管子的最短长度,结果取整。

样例输入

2 98.1789
42.8602 28.7622

3 747.702
339.687 191.953 330.811

0 0

样例输出

138
1628

题目来源

“IBM南邮杯”团队赛2009


//玻璃球 【深蓝】——集合DP
#include<iostream>
#include<cmath>
using namespace std;
/*
int main()
{
double r1 = 42.8602, r2 = 28.7622, d = 98.1789;
double ans;
ans = r1 + r2 + sqrt((r1+r2)*(r1+r2) - (d-r1-r2)*(d-r1-r2));
printf("%f\n",ans);

return 0;
}
*/

double dp[1<<15][15];
bool vis[1<<15];
int n;
double d, r[15];

double cal(double r1, double r2)
{
	return sqrt((r1+r2)*(r1+r2) - (d-r1-r2)*(d-r1-r2));
}

void dfs(int cur) // !!!
{
	int t = 1;
	for(int i=0;i<n;i++)
	{
		if(cur&t)
		{
			if(cur^t)
			{
				if(!vis[cur^t]) dfs(cur^t);
			}
			else
			{
				dp[cur][i] = 2 * r[i];
				return;
			}
			vis[cur^t] = true;
			for(int j=0;j<n;j++)
				dp[cur][i] = min(dp[cur][i], dp[cur^t][j]+cal(r[j], r[i])-r[j]+r[i]);
		}
		t = t<<1;
	}
}

int main()
{
	while(scanf("%d%lf",&n,&d) && n)
	{
		for(int i=0;i<n;i++)
			scanf("%lf",&r[i]);
		int m = 1<<n; // 2^n

		memset(vis, false, sizeof(vis));
		//dp[i][j]表示j个球需要的管子的最短长度
		for(int i=0;i<m;i++)
			for(int j=0;j<n;j++)
				dp[i][j] = 15000; // d<=1000.0
		dfs(m-1); // 最大的
		double ans = 1e9;
		for(int i=0;i<n;i++)
			if(ans > dp[m-1][i])
				ans = dp[m-1][i];

		printf("%d\n",(int)(ans+0.5)); // 四舍五入,以前写的好麻烦!int不能省
	}

	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值