zoukankan      html  css  js  c++  java
  • NOJ 1118 玻璃球 【深蓝】[状态压缩DP]

    玻璃球 【深蓝】

    时间限制(普通/Java) : 10000 MS/ 30000 MS 运行内存限制 : 65536 KByte
    总提交 : 57            测试通过 : 11

    比赛描述

    玩过玻璃球游戏吗?sed同学小学没有毕业之前玩过,他常常用一个直径为d的圆柱管来装玻璃球,已知每个玻璃球是半径为 r1, r2, . . . , rn的球体,他当时一直有一个疑问:装这些玻璃球最少需要多长的圆柱管。现请你帮他解决这个问题。

    假设玻璃球半径充分大,以至于管中不存在三个可以同时相互接触的玻璃球。给定这样的限制,表示玻璃球将总以这样的方式装入:他们的中心点位于含导管旋转轴的2维平面上。

    输入

    输入包含多个测试例。每个测试例包括两行。每个测试例的第一行包含一个整数n (1 ≤ n ≤ 15) ,表示sed持有玻璃球的数目,还有一个浮点值d (2.0 ≤ d ≤ 1000.0) ,表示管子直径。两值以空格隔开。每个测试例的第二行包含n个由空格分隔的浮点数r1 r2 . . . rn(1.0 ≤ ri ≤ d/2) ,为sed玻璃球的半径。一个空白行分隔所以输入测试例。一行“0 0”表示输入结束,无需处理此例。

    输出

    对于每个输入测试例,打印管子的最短长度,结果取整。(四舍五入取整)

    样例输入

    2 98.1789
    42.8602 28.7622
    3 747.702
    339.687 191.953 330.811
    0 0

    样例输出

    138
    1628

    最终长度等于第一个球的半径 + 最后一个球的半径 + 中间相邻的球产生的高度。

    又是一道状态压缩的题目,dp[status][i]表示的是在选择玻璃球已经放入圆柱管的情况下,最上面的球是第i个球的最小长度

    状态转移方程 d[status][i] = d[status ^ (1 << i)][j] – d[j] +d[i] +height(i,j),其中 i 存在于在状态status中,j不存在于status中,height(i,j)相邻着放所产生的长度。

    #include <iostream>
    #include <stdio.h>
    #include <math.h>
    #include <string.h>
    
    using namespace std;
    double d;
    int n;
    double r[20];
    
    double calheight(int i, int j)
    {
        double l = r[i] + r[j];
        double a = d - l;
        return sqrt(l*l - a*a);
    }
    
    double dp[1 << 16 |1][16]; //状态status下  i在最上面的最小值
    //dp[status][j]=dp[status ^ (1 << j)][i] - r[i] + cal(i,j) + r[j] ;
    
    bool read()
    {
        scanf("%d%lf", &n, &d);
        if(n == 0 && d == 0) return false;
        for(int i = 0; i < n; i++)
            scanf("%lf", &r[i]);
        return true;
    }
    
    int solve()
    {
        memset(dp, 0, sizeof(dp));
        for(int s = 0; s < (1 << n); s++)
        {
            for(int i = 0; i < n; i++)
            {
                if(s & (1<<i)) continue;
                if(s)
                    dp[s ^ (1<<i)][i] = 1000000000;
                else
                    dp[s ^ (1<<i)][i] = r[i] + r[i];
                for(int j = 0; j < n; j++)
                {
                    if(s & (1<<j))
                    {
                        dp[s ^ (1 << i)][i] = min(dp[s ^ (1<<i)][i], dp[s][j] - r[j] + r[i] + calheight(i,j));
                    }
                }
            }
        }
        double ans = 1000000000;
        for(int i = 0; i < n; i ++)
        {
            ans =min(ans, dp[((1 << n) - 1)][i]);
        }
        printf("%.0f
    ", (ans));
    
    }
    
    int main()
    {
        while(read())
        {
            solve();
        }
        return 0;
    }
    如果有错误,请指出,谢谢
  • 相关阅读:
    (转)三款Json查看小工具
    开源数据源
    关于异常
    java 线程池
    百度android面试及一些问题的讲解
    linux常用命令
    android activityManager
    Android ListView及其属性
    android listView与adapter
    android 反编译
  • 原文地址:https://www.cnblogs.com/Alruddy/p/7124272.html
Copyright © 2011-2022 走看看