题目链接: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. jenkins配置sonarqube

    jenkins配置sonarqube 下载插件SonarQube Scanner for Jenkins 在系统管理系统设置中选择 SonarQube servers 配置服务器名称.访问URL地址, ...

  2. python manage.py syncdb Unknown command: 'syncdb'问题解决方法

    在django1.9后的版本中,python manage.py syncdb命令修改为python manage.py migrate,执行正常. 选择sqlite可视化sqlitestudio-3 ...

  3. Maven入门-依赖管理(Jar包管理)(二)

    1       依赖管理(Jar包管理) 1.添加依赖  

  4. C++中构造函数和析构函数的调用顺序

    一般而言,析构函数调用的顺序和构造函数调用顺序相反,但是,对象的存储类别可以改变调用析构函数的顺序.举例说明: CreateAndDestroy类的定义 CreateAndDestroy类的成员函数的 ...

  5. AutoMapper中用户自定义转换

    Custom Type Converters Sometimes, you need to take complete control over the conversion of one type ...

  6. 求web前端面试题库及答案

    1.对WEB标准以及W3C的理解与认识 标签闭合.标签小写.不乱嵌套.提高搜索机器人搜索几率.使用外 链css和js脚本.结构行为表现的分离.文件下载与页面速度更快.内容能被更多的用户所访问.内容能被 ...

  7. SciPy模块应用

    1.图像模糊  图像的高斯模糊是非常经典的图像卷积例子.本质上,图像模糊就是将(灰度)图像I 和一个高斯核进行卷积操作:,其中是标准差为σ的二维高斯核.高斯模糊通常是其他图像处理操作的一部分,比如图像 ...

  8. python httplib和urllib的性能比较

    httplib代码: urlParseResult = urlparse(url) host = urlParseResult.hostname path = urlParseResult.path ...

  9. MFC 使用用指定USB设备串口

    在做设备串口通讯时,往往需要自动连接到想要连接的usb转串口设备上. #include <Setupapi.h> int CMFCApplication1Dlg::FindUSBCOM() ...

  10. MySQL中adddate学习

    -- 修改时间:ADDDATE(date,INTERVAL expr unit) -- 含义:date时间,expr 表达式值,unit表达式对应的时间单位 -- unit : SECOND,MINU ...