UVA10012把圆放进矩形的底部求矩形的最短长度

这题刚开始做的时候,想都没想就直接敲了一个求排列后直接按照每个圆和前一个圆相切的思路算了一遍,

果断WA了,然后想了想,一个很大的圆可以挡到很多小的圆,然后想了很久不知道怎么写了,然而实际上也很简单,

记录每个圆的横坐标,每放一个圆,求这个圆的最长的坐标,即这个圆分别与前面的圆相切的坐标和这个圆的半径比较

取最大值,这样就不需要去确定左边界了,直接可以求出长,就是计算每个点的横坐标加上半径取最大值就行了。

后来想了一下,其实也没必要写递归,就是刚开始的思路求排列就能够解决,只是这里知道圆放置的顺序之后,需要知道每个圆

放置的方式,怎么去知道,就开一个数组存每个圆的横坐标,求这个圆和前面相切的最大横坐标,然后加上半径最大的那个就是

长度,其实这个思路起初WA了之后我有想过,但是可能想多了,我想到了这个圆假如和前面的圆相切之后会不会和这俩个圆之间

的圆相交,或者说这个圆和前面的圆相切的时候会不会不和地面接触等等,然后就没敢敲代码,看来有时候有些东西自己想的不一定就是

对的,最好敲代码去验证。

1:递归代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <map>
#include <set>
#include<cmath>
#include<climits>
#include<cfloat>
using namespace std;
const int P = 1e9 + 7;
double a[10],c[10],A[10];
int m;
double ans;
int vis[10];
void dfs(int cur)
{
    if(cur==m)
    {
       // for(int i=0;i<m;i++)
      //  {
      //      double temp=A[i]-c[i];
       //     if(temp>0.0)
      //          for(int j=0;j<m;j++)
       //             c[j]+=temp;
      //  }
        double res=0.0;
        for(int i=0;i<m;i++)
        {
            double temp=A[i]+c[i];
            res=max(temp,res);
        }
        ans=min(res,ans);
    }
    for(int i=0;i<m;i++)
    {
        if(!vis[i])
        {
            vis[i]=1;
            A[cur]=a[i];
            c[cur]=a[i];
            for(int j=0;j<cur;j++)
            {
                double temp=c[j]+2*sqrt(A[cur]*A[j]);
                c[cur]=max(temp,c[cur]);
            }
            dfs(cur+1);
            vis[i]=0;
        }
    }
}
int main()
{
    int n;
    cin>>n;
    while(n--)
    {
       cin>>m;
       for(int i=0;i<m;i++)
        scanf("%lf",&a[i]);
        memset(vis,0,sizeof(vis));
        ans=DBL_MAX;
        dfs(0);
        printf("%.3f\n",ans);
    }
    return 0;
}

2:全排列代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <map>
#include <set>
#include<cmath>
#include<climits>
#include<cfloat>
using namespace std;
const int P = 1e9 + 7;
double a[10];
int m;
double ans;
int main()
{
    int n;
    cin>>n;
    while(n--)
    {
       cin>>m;
       for(int i=0;i<m;i++)
        scanf("%lf",&a[i]);
       // memset(vis,0,sizeof(vis));
        ans=DBL_MAX;
        sort(a,a+m);
        do
        {
            double c[10];
            for(int i=0;i<m;i++)
            {
                c[i]=a[i];
                for(int j=0;j<i;j++)
                {
                    double temp=c[j]+2*sqrt(a[i]*a[j]);
                    c[i]=max(temp,c[i]);
                }
            }
            double res=0.0;
            for(int i=0;i<m;i++)
                res=max(res,a[i]+c[i]);
            ans=min(res,ans);
        }while(next_permutation(a,a+m));
        //dfs(0);
        printf("%.3f\n",ans);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值