题目链接:https://vjudge.net/contest/210334#problem/G

转载于:https://blog.csdn.net/todobe/article/details/54171920

题目描述: 
给出房间的宽度r和s个挂坠的重量wi,设计一个尽量宽(但宽度不能超过房间宽度r)的天平,挂着所有挂坠。 
天平由一些长度为1的木棍组成。木棍的每一端要么挂一个挂坠,要么挂另外一个木棍。如图1所示,设n和m分别是两端的总重量,要让天平平衡,必须满足n*a=m*b。

例如:如果有3个重量分别为1,1,2的挂坠,有3种平衡的天平,如下图所示:

挂坠的宽度忽略不计,且不同的子天平可以相互重叠。如下图所示,宽度为(1/3)+1+(1/4)。 

输入格式: 
输入第一行为数据组数。每组数据前两行为房间宽度r和挂坠数目s (0 < r < 10,1<=s<=6)。以下s行为一个挂坠的重量wi(1<=wi<=1000)。输入保证不存在天平的宽度恰好在r-10^(-5)和r+10^(-5)(这样可以保证不会出现精度问题)。

输出格式: 
对于每组数据,输出最优天平的宽度。如果无解,输出-1。你的输出和标准答案的绝对误差不应超过10^(-8)

题目分析:(搜索) 
天平的形态最后可以看成二叉树,所以问题转化成了我们有一堆点(点数还不超过6),要把这一堆点合成一颗树。我们可以用哈弗曼树的想法,每次把两个节点合成一个新的节点,最终只剩下一个节点,就是一组可行解,更新答案。

但是我们不知道每次要合并哪两个点,因为层数很少,所以可以暴力枚举。

这是huffman合并思想

#include<cstdio>
#include<iostream>
#include <algorithm>
using namespace std;
struct balance              //形象的定义一个带有宽度的'节点',若该节点不是由节点合并而来的,则ls,和rs为0(因为点的左宽和右宽为0),如果是由其他结点合并而来的,则宽度按照实际宽度更新
{
    double w, ls, rs;
    balance operator + (const balance c)
    {
        balance z;
        z.w = w + c.w;
        double l = c.w / (w + c.w);             //木棍左边的长度为,右边的点的重量/(两点的重量之和)
        double r = w / (w + c.w);               //同理
        z.ls = max(l + ls, c.ls - r);           //比较右边点的左边界和左边点的左边界哪个更靠左,因为完全有可能右边点的左边界比左边点的左边界还要靠左
        z.rs = max(r + c.rs, rs - l);           //同理
        return z;
    }
}a[];

double r, ans;
int s, T;

void dfs(int c)
{
    if (c == s)        //n个节点最终加到1个节点只需加n-1次
    {
        ].ls + a[].rs;           //利用huffman原理,将树的所有节点最终合成一个'节点',整个天平的宽度即为这个‘节点’的宽度
        if (cs <= r && cs>ans) ans = cs;
        return;
    }
    balance b[], d[];
    ; i <= s - c + ; i++) b[i] = a[i];         //记录下当前所枚举的各点的情况
    ; i <= s - c + ; i++)                //这个循环我没弄明白
        ; j <= s - c + ; j++)
        {
            if (i == j) continue;
            ; k <= s - c + ; k++) a[k] = b[k];     //重置为刚才用b[]数组记录下的当前c值得情况
            ;
            ; k <= s - c + ; k++)
                if (k != i && k != j) d[++top] = a[k];
            d[++top] = a[i] + a[j];
            ; k <= top; k++) a[k] = d[k];
            dfs(c + );
        }
}

int main()
{
    scanf("%d", &T);
    while (T--)
    {
        scanf("%lf%d", &r, &s);
        ; i <= s; i++)
        {
            scanf("%lf", &a[i].w);
            a[i].ls = ;
            a[i].rs = ;
        }
        ans = -;
        dfs();
        printf("%.10lf\n", ans);
    }
    ;
}

这是枚举子集思想

  1. &表示交集,^表示差集,|表示并集。
  2. 利用交集是否为0还可以判断是否存在包含关系。
  3. 递归枚举
#include<cstdio>
#include<cstring>
#include<vector>
#include <algorithm>
using namespace std;

struct Tree {
    double L, R; // distance from the root to the leftmost/rightmost point
    Tree() :L(), R() {}
};

;

 << maxn];
 << maxn];
vector<Tree> tree[ << maxn];

void dfs(int subset) {
    if (vis[subset]) return;
    vis[subset] = true;

    bool have_children = false;//初始化
    )&subset; left; left = (left - )&subset) {//遍历每一种情况,取subset的子集所以要取交集,从上一个的集合再取交集可以提高效率
        have_children = true;//进入循环表明有子集

        int right = subset ^ left;//得到差集
        double d1 = sum[right] / sum[subset];//公示推导出来的
        double d2 = sum[left] / sum[subset];

        dfs(left); dfs(right);

        ; i < tree[left].size(); i++)
            ; j < tree[right].size(); j++) {
                Tree t;
                t.L = max(tree[left][i].L + d1, tree[right][j].L - d2);//判断两个支路哪个更长。
                t.R = max(tree[right][j].R + d2, tree[left][i].R - d1);
                if (t.L + t.R < r) tree[subset].push_back(t);
            }
    }

    if (!have_children) tree[subset].push_back(Tree());
}

int main() {
    int T;
    scanf("%d", &T);
    while (T--) {
        scanf("%lf%d", &r, &n);
        ; i < n; i++) scanf("%lf", &w[i]);
        ; i < ( << n); i++) {//遍历每一种可能
            sum[i] = ;
            tree[i].clear();
            ; j < n; j++)
                 << j)) sum[i] += w[j];//把这个集合中的质量都加起来,包含第j个质量的集合。
        }

         << n) - ;//全部都是1
        memset(vis, , sizeof(vis));
        dfs(root);

        ;
        ; i < tree[root].size(); i++)
            ans = max(ans, tree[root][i].L + tree[root][i].R);//找到最大值
        printf("%.10lf\n", ans);
    }
    ;
}

2018-04-16

uva1354 天平难题 【位枚举子集】||【huffman树】的更多相关文章

  1. UVa 1354 天平难题 (枚举二叉树)

    题意: 分析: 其实刚看到这题的时候觉得很难, 以至于结束了第七章然后去做了一遍第六章树的部分.现在再做这题觉得思路并不是太难,因为总共就只有六个结点,那么只要枚举二叉树然后算出天平然后再从叶子往上推 ...

  2. [数据结构与算法]哈夫曼(Huffman)树与哈夫曼编码

    声明:原创作品,转载时请注明文章来自SAP师太技术博客( 博/客/园www.cnblogs.com):www.cnblogs.com/jiangzhengjun,并以超链接形式标明文章原始出处,否则将 ...

  3. 【bzoj2073】【[POI2004]PRZ】位运算枚举子集的特技

    (上不了p站我要死了) Description 一只队伍在爬山时碰到了雪崩,他们在逃跑时遇到了一座桥,他们要尽快的过桥. 桥已经很旧了, 所以它不能承受太重的东西. 任何时候队伍在桥上的人都不能超过一 ...

  4. UVA1354-Mobile Computing(二进制枚举子集)

    Problem UVA1354-Mobile Computing Accept:267  Submit:2232 Time Limit: 3000 mSec  Problem Description ...

  5. NOI 2015 荷马史诗【BZOJ 4198】k叉Huffman树

    抱歉因为NOIP集训,好长时间没再写题解了. NOI 2015也就只有这道题一看就能懂了-- 4198: [Noi2015]荷马史诗 Time Limit: 10 Sec  Memory Limit: ...

  6. HUFFMAN 树

    在一般的数据结构的书中,树的那章后面,著者一般都会介绍一下哈夫曼(HUFFMAN) 树和哈夫曼编码.哈夫曼编码是哈夫曼树的一个应用.哈夫曼编码应用广泛,如 JPEG中就应用了哈夫曼编码. 首先介绍什么 ...

  7. Huffman树及其应用

    哈夫曼树又称为最优二叉树,哈夫曼树的一个最主要的应用就是哈夫曼编码,本文通过简单的问题举例阐释哈夫曼编码的由来,并用哈夫曼树的方法构造哈夫曼编码,最终解决问题来更好的认识哈夫曼树的应用--哈夫曼编码. ...

  8. [数据结构] 2.2 Huffman树

    注:本文原创,转载请注明出处,本人保留对未注明出处行为的责任追究. 1.Huffman树是什么 Huffman树也称为哈夫曼编码,是一种编码方式,常用于协议的制定,以节省传输空间. A - F字母,出 ...

  9. 数据结构与算法(周鹏-未出版)-第六章 树-6.5 Huffman 树

    6.5 Huffman 树 Huffman 树又称最优树,可以用来构造最优编码,用于信息传输.数据压缩等方面,是一类有着广泛应用的二叉树. 6.5.1 二叉编码树 在计算机系统中,符号数据在处理之前首 ...

随机推荐

  1. D - Laying Cables Gym - 100971D (单调栈)

    题目链接:https://cn.vjudge.net/problem/Gym-100971D 题目大意:给你n个城市的信息,每一个城市的信息包括坐标和人数,然后让你找每一个城市的父亲,作为一个城市的父 ...

  2. linux bash的重定向

    cnblogs原创 下面几种bash重定向各表示什么意思? find / -name passwd > /dev/null >& > /dev/null find / -na ...

  3. FPN-Feature Pyramid Networks for Object Detection

    FPN-Feature Pyramid Networks for Object Detection 标签(空格分隔): 深度学习 目标检测 这次学习的论文是FPN,是关于解决多尺度问题的一篇论文.记录 ...

  4. 解决ipad连接不上电脑的问题

    检查一下信息: 1.iTunes是否安装 2.数据线是否完好 3.检查下图中的两个设备是否开启 4.最后一步是最恶心的:是否关闭了防火墙!!!! 操作步骤如下图示 我就是因为打开了防火墙,所以一直连接 ...

  5. linux matlab2016 安装

    1. 下载Matlab 2016b 下载文件夹中包含三个文件:Matlab 2016b Linux64 Crack.rar,R2016b_glnxa64_dvd1.iso,R2016b_glnxa64 ...

  6. SpringBoot整合国际化功能

    (1).编写国际化配置文件 在resources下新建i18n文件夹,并新建以下文件 ①index.properties   username=username ②index_en_US.proper ...

  7. 【转】Python流程控制语句

    [转]Python流程控制语句 人们常说人生就是一个不断做选择题的过程:有的人没得选,只有一条路能走:有的人好一点,可以二选一:有些能力好或者家境好的人,可以有更多的选择:还有一些人在人生的迷茫期会在 ...

  8. 身份证号校验原理及JavaScript实现

          在网站中,总有各种各样的表单,用户使用表单来向服务器发送数据,进行交互. 然而,代代相传的经验是,永远不要信任用户的输入,一定要对数据进行验证.如果使用不经验证的表单,轻则会有大量无效提交 ...

  9. springboot系列三、springboot 单元测试、配置访问路径、多个配置文件和多环境配置,项目打包发布

    一.单元测试 生成的demo里面包含spring-boot-starter-test :测试模块,包括JUnit.Hamcrest.Mockito,没有的手动加上. <dependency> ...

  10. dellR720服务器设置光盘引导流程安装cenos7

    1.开机,按F10,进入系统引导界面,选择加载系统选项,并选择redhat 7.1选项 系统提示不支持,选择仍然继续,根据提示设置BIOS设置启动,重启 2.根据提示按F11进入BIOS启动设置,选择 ...