UVA_10012
这个题目WA得满痛苦的,一开始不知道为什么会WA,后来意识到原来是少考虑了两个相邻的圆半径差别很大的情况,也就是说一个大圆下面可能可以放很多小圆,这时就又没头绪了。
后来看了别人的代码后,给了我很大的启发,原来可以在递归的过程中多引入一个表示当前放置的圆的圆心坐标的数组,来辅助计算。
我们以左下角为原点建立直角坐标系,暂且假设第一个圆是紧贴左下角放置的,然后用深搜枚举每个位置可能放的圆,并计算放置这个圆的圆心坐标。计算的时候要依次假设当前圆和前面的某一个圆相切,并依此来计算当前圆的圆心坐标,最后取所有结果的最大值,这样就得到了当前圆的放置时的实际的圆心坐标。
在放置完所有圆后,实际上可能存在某些圆的一部分是在y轴左半部分的,因而要求我们再遍历一遍所有放置好的圆,找到所有圆最左边点的位置,并记录成矩形的左边界,或者把y轴更新到这个位置上,也就是说要把所有圆的圆心坐标加上计算所得的值,这样就保证了x=0是矩形的左边的边界。之后就是计算右边的边界,同样,我们需要遍历一遍所有放置好的圆,找到所有圆最右边点的位置,把这个位置作为矩形右边的边界即可。
#include<stdio.h>
#include<string.h>
#include<math.h>
int n,vis[10];
double a[10],A[10],c[10],ans;
void dfs(int cur)
{
int i,j;
double move,temp,res;
if(cur==n)
{
move=0.0;
for(i=0;i<n;i++)
{
temp=A[i]-c[i];
if(temp>move)
move=temp;
for(j=0;j<n;j++)
c[j]+=move;
}
res=0.0;
for(i=0;i<n;i++)
{
temp=c[i]+A[i];
if(temp>res)
res=temp;
}
if(res<ans)
ans=res;
return;
}
for(i=0;i<n;i++)
if(!vis[i])
{
A[cur]=a[i];
c[cur]=0.0;
for(j=0;j<cur;j++)
{
temp=c[j]+2*sqrt(A[cur]*A[j]);
if(temp>c[cur])
c[cur]=temp;
}
vis[i]=1;
dfs(cur+1);
vis[i]=0;
}
}
int main()
{
int i,j,k,t;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
for(i=0;i<n;i++)
scanf("%lf",&a[i]);
ans=1000000000.0;
memset(vis,0,sizeof(vis));
for(i=0;i<n;i++)
{
A[0]=a[i];
c[0]=a[i];
vis[i]=1;
dfs(1);
vis[i]=0;
}
printf("%.3f\n",ans);
}
return 0;
}