10012 How Big Is It?(****)

/*
题意:一堆小球,要求使用最小的矩形将它们全部装起来。
要求小球必须接地,至少与其他一个小球相邻
思路:涉及到状态转移,用到动态规划思想。原来通过深搜,剪枝结果WA,后来想到两个相邻小球半径相差很大的情况,于是没有了做题思路。看别人代码后,搜索中添加两个数组,A[i]表示第i个小球的半径大小,c[i]表示第i个小球排完后右边界最远的位置。于是有状态转移方程:  c[i]=max(c[j]+2*sqrt(A[j]*A[i])|j为第i个之间的小球),最后需要检查一次左边界和右边界,可能出现左边界左移的情况,所以只要让c[i]都加上左移的距离即可!
*/

//错误代码:
#include <cstdio>
#include <cstring>
#include <cmath>
bool visit[10];
int T,n;
double radii[10];
double min;
int A[10],result[10];
void dfs(int now,int dep,double length)
{
	A[dep-1]=now;
	if(length>=min) return;
	if(dep==n)
	{
		if(length+radii[now]<min)
		{
			min=length+radii[now];
			memcpy(result,A,sizeof(A));
		}
	}
	for(int i=0;i<n;i++)
	{
		if(!visit[i])
		{
			visit[i]=1;
			dfs(i,dep+1,length+2*sqrt(radii[now]*radii[i]));
			visit[i]=0;
		}

	}
}
int main()
{
	freopen("data.in","r",stdin);
	freopen("data.out","w",stdout);
	scanf("%d",&T);
	while(T--)
	{
		scanf("%d",&n);
		for(int i=0;i<n;i++)
			scanf("%lf",&radii[i]);
		min=1e10;
		memset(visit,0,sizeof(visit));
		for(int i=0;i<n;i++)
		{
			visit[i]=1;
			dfs(i,1,radii[i]);
		}
		for(int i=0;i<n;i++)
			printf("%d ",result[i]);
		printf("\n");
		printf("%.3lf\n",min);
	}
	return 0;
}


//正解:
#include <cstdio>
#include <cmath>
#include <cstring>
double A[10],c[10];
double radii[10];
int n;
bool visit[10];
double ans;
void dfs(int cur)
{
	if(cur==n)
	{
		double move=0.0;
		for(int i=0;i<n;i++)
		{
			double temp=A[i]-c[i];
			if(temp>move)
				move=temp;
		}
		for(int i=0;i<n;i++)
			c[i]+=move;
		double res=0.0;
		for(int i=0;i<n;i++)
		{
			double temp=A[i]+c[i];
			if(temp>res)
				res=temp;
		}
		if(res<ans)
			ans=res;
		return;
	}
	for(int i=0;i<n;i++)
		if(!visit[i])
		{
			visit[i]=1;
			A[cur]=radii[i];
			c[cur]=0.0;
			for(int j=0;j<cur;j++)
			{
				double temp=c[j]+2*sqrt(A[cur]*A[j]);
				if(c[cur]<temp)
					c[cur]=temp;
			}
			dfs(cur+1);
			visit[i]=0;
		}
}
int main()
{
	freopen("data.in","r",stdin);
	int T;
	scanf("%d",&T);
	while(T--)
	{
		scanf("%d",&n);
		for(int i=0;i<n;i++)
			scanf("%lf",&radii[i]);
		memset(visit,0,sizeof(visit));
		ans=1e10;
		for(int i=0;i<n;i++)
		{
			A[0]=radii[i];
			c[0]=radii[i];
			visit[i]=1;
			dfs(1);
			visit[i]=0;
		}
		printf("%.3lf\n",ans);
	}
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值