UVA 10012 - How Big Is It 暴力 回溯 全排列

6 篇文章 0 订阅
4 篇文章 0 订阅
暴力解法
8个圆   全排列  一个个判断

回溯  也是全排列的思想  但是在进行排列的时候取一个最小的  如果还没有排完就已经比最小的还大  那么后面的所有以此为基础的答案都可以舍去
不用判断

上面的大体思路是正确的  但是忽略了一个问题  那就是排列中两个相邻的圆一定相切吗?  答案是否定的 

所以我们还需要考虑两个圆不相切的情况     那这样怎么才能确定当前圆应该放在哪个位置   可以想象到  放的当前圆一定是离原点最远 而且
还与前面的某一个圆相切   这样不难判断这一个圆的位置   直接枚举计算当前圆和前面每个园相切时圆的位置  保存离原点最远的一个

保存每个圆的最左位置和最右位置   循环一遍找到位置最左  和位置最右  两个相减就是当前排列所需要盒子的宽度

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
const int maxn = 10;

double Dis(double R,double r)
{
    return 2*sqrt(R*r);
}

struct Point
{
    double x,y,l,r;
};

int main()
{
    #ifdef LOCAL
    freopen("in.txt","r",stdin);
    #endif // LOCAL
    int n,m;
    scanf("%d",&n);
    while(n--)
    {
        scanf("%d",&m);
        double  R[m];
        for(int i = 0; i < m; i++)
            scanf("%lf",&R[i]);
        double  MIN = 0x3f3f3f3f,t;
        sort(R,R+m);
        do
        {
            struct Point O,P[m];
            double Left_len = 0x3f3f3f3f ,Right_len = -0x3f3f3f3f;
            O.x = O.y = 0;
            P[0].x = P[0].y = R[0];
            P[0].l = 0;
            P[0].r = 2*R[0];
            for(int i = 1; i < m; i++)
            {
                double t = -0x3f3f3f3f; /// 不用判断y的位置 只需要判断x距离原点的位置即可
                for(int j = 0; j < i; j++)
                {
                    double temp = Dis(R[j],R[i]);
                    if(t < (temp + P[j].x)) t = temp + P[j].x;
                }
                P[i].x = t;
                P[i].y = R[i];
                P[i].l = P[i].x - R[i];
                P[i].r = P[i].x + R[i];
            }
            for(int i = 0; i < m; i++)
            {
                if(Left_len > P[i].l) Left_len = P[i].l;
                if(Right_len < P[i].r) Right_len = P[i].r;
            }
            if(MIN > (Right_len - Left_len)) MIN = Right_len - Left_len;
        }while(next_permutation(R,R+m));
        printf("%.3lf\n",MIN);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值