uva--10012

来源:互联网 发布:红外触摸算法 编辑:程序博客网 时间:2024/06/05 05:41
题意:

    给n个半径已知的小球,要将他们放到一个箱子中去,要求每个小球必须和箱子的底部接触并且每个小球必须至少要和一个小球接触,求箱子的最小长度。

思路:

   开始时觉得第一个小球和最后一个小球必须要和箱子相切,然后中间的小球必须要和它两边的小球相切,所以只需要

求出n个小球的全排列,然后对一个排列计算一次,再从结果中取最小值就行了。然后WA了几次后才发现这个思路有漏洞

:中间的球不一定要和它两边的球相切,可能有两个半径很大的球相切然后中间放了几个小球。然后照着这个思路改了代码

然后交了之后又WA了。后面看了别人的题解后发现按假定第一个球和左边界相切的情况下,后面的球有可能有一部分在y轴的左边

。所以计算箱子的长度时需要把排列好的小球的左右x边界求出来才能计算出箱子的长度,而不能直接用最后一个球的横坐标加上其半径来计算。

这个题目dfs和全排列都是可以做的(其实本质上是一样的)。

注意:

    由这个题目来讲的话,要注意思维的严谨性;本来我通过样例已经发现如果按照上面的算法,当第一个球很小的时候,第二个球的圆心坐标要小于它的半径值,应该是存在

问题的;然后我就直接对第二个球的坐标进行了修正就提交了,当然有WA了一次;其实这个时候就应该想到如果第一二个小球都很小那么第三个小球也有可能在y轴的左边,

这根本就不是特判所能解决的。

 

代码如下:

#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;

double r[10],ans;
int n,vis[10];

typedef struct
{
    double x,y;
    double r;
}P;
P p[10];

void dfs(int cur)
{
    int i,j;
    if(cur==n)
    {
        double temp1=10000000.0,temp2=0.0,temp;
        for(i=0;i<n;i++)
        {
            if(p[i].x-p[i].r<temp1)
                temp1=p[i].x-p[i].r;
            if(p[i].x+p[i].r>temp2)
                temp2=p[i].x+p[i].r;
        }
        temp=temp2-temp1;
        if(ans>temp)
           ans=temp;
        return ;
    }
    for(j=0;j<n;j++)
    {
        double x0,x=0.0;
        if(!vis[j])
        {
            for(i=0;i<cur;i++)
            {
                double m=(p[i].r+r[j])*(p[i].r+r[j]);
                double k=(p[i].y-r[j])*(p[i].y-r[j]);
                x0=sqrt(m-k)+p[i].x;
                if(x<x0) x=x0;
            }
            p[cur].x=x; p[cur].y=r[j]; p[cur].r=r[j];
            vis[j]=1;
            dfs(cur+1);
            vis[j]=0;
        }
    }

}

int main()
{
    int i,j,t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        for(i=0;i<n;i++)
            scanf("%lf",&r[i]);
        ans=10000000000.0;
        for(i=0;i<n;i++)
        {
            memset(vis,0,sizeof(vis));
            p[0].x=p[0].y=p[0].r=r[i];
            vis[i]=1;
            dfs(1);
        }
        printf("%.3lf\n",ans);
    }
 return 0;
}

下面是全排列做的代码:

#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;

int m;
double temp[10];

typedef struct
{
    double x,y,r;
}P;
P p[10];

double f(int d[])
{
   int i,j;
   double x0,y0,x1,y1,r0,r1,ans=0,x=0;
   p[1].x=temp[d[1]]; p[1].r=temp[d[1]]; p[1].y=temp[d[1]];
   for(i=2;i<=m;i++)
   {
       r1=temp[d[i]]; y1=temp[d[i]];
       for(j=1;j<i;j++)
       {
          r0=p[j].r;
          y0=p[j].y;
          x0=p[j].x;
          double t=(r1+r0)*(r1+r0)-(y1-y0)*(y1-y0);
          x1=sqrt(t)+x0;
          if(x<x1)
            x=x1;
       }
       if(i==2&&x<temp[d[2]])
           x=temp[d[2]];
       p[i].x=x; p[i].y=y1; p[i].r=r1;
       if(ans<x+r1)
          ans=x+r1;
   }
    double temp1=100000000.0,temp2=0;
    for(i=1;i<=m;i++)
    {
        if(p[i].x-p[i].r<temp1)
            temp1=p[i].x-p[i].r;
        if(p[i].x+p[i].r>temp2)
            temp2=p[i].x+p[i].r;
    }
    ans=temp2-temp1;
   return ans;
}

int main()
{
    int i,j,t,d[10];
    double ans;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&m);
        for(i=1;i<=m;i++)
        {
            d[i]=i;
            scanf("%lf",&temp[i]); //注意double类型输入必须为"%lf"而不能是"%f"
        }
        ans=10000000000+0.0;
        do
        {
            double k=f(d);
            if(ans>k)
                ans=k;
        }while(next_permutation(d+1,d+m+1));
        printf("%.3lf\n",ans);
    }
  return 0;

}

0 0
原创粉丝点击