uva1354 天平难题 【位枚举子集】||【huffman树】
题目链接: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); } ; }
这是枚举子集思想
- &表示交集,^表示差集,|表示并集。
- 利用交集是否为0还可以判断是否存在包含关系。
- 递归枚举
#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;//初始化 )⊂ 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树】的更多相关文章
- UVa 1354 天平难题 (枚举二叉树)
题意: 分析: 其实刚看到这题的时候觉得很难, 以至于结束了第七章然后去做了一遍第六章树的部分.现在再做这题觉得思路并不是太难,因为总共就只有六个结点,那么只要枚举二叉树然后算出天平然后再从叶子往上推 ...
- [数据结构与算法]哈夫曼(Huffman)树与哈夫曼编码
声明:原创作品,转载时请注明文章来自SAP师太技术博客( 博/客/园www.cnblogs.com):www.cnblogs.com/jiangzhengjun,并以超链接形式标明文章原始出处,否则将 ...
- 【bzoj2073】【[POI2004]PRZ】位运算枚举子集的特技
(上不了p站我要死了) Description 一只队伍在爬山时碰到了雪崩,他们在逃跑时遇到了一座桥,他们要尽快的过桥. 桥已经很旧了, 所以它不能承受太重的东西. 任何时候队伍在桥上的人都不能超过一 ...
- UVA1354-Mobile Computing(二进制枚举子集)
Problem UVA1354-Mobile Computing Accept:267 Submit:2232 Time Limit: 3000 mSec Problem Description ...
- NOI 2015 荷马史诗【BZOJ 4198】k叉Huffman树
抱歉因为NOIP集训,好长时间没再写题解了. NOI 2015也就只有这道题一看就能懂了-- 4198: [Noi2015]荷马史诗 Time Limit: 10 Sec Memory Limit: ...
- HUFFMAN 树
在一般的数据结构的书中,树的那章后面,著者一般都会介绍一下哈夫曼(HUFFMAN) 树和哈夫曼编码.哈夫曼编码是哈夫曼树的一个应用.哈夫曼编码应用广泛,如 JPEG中就应用了哈夫曼编码. 首先介绍什么 ...
- Huffman树及其应用
哈夫曼树又称为最优二叉树,哈夫曼树的一个最主要的应用就是哈夫曼编码,本文通过简单的问题举例阐释哈夫曼编码的由来,并用哈夫曼树的方法构造哈夫曼编码,最终解决问题来更好的认识哈夫曼树的应用--哈夫曼编码. ...
- [数据结构] 2.2 Huffman树
注:本文原创,转载请注明出处,本人保留对未注明出处行为的责任追究. 1.Huffman树是什么 Huffman树也称为哈夫曼编码,是一种编码方式,常用于协议的制定,以节省传输空间. A - F字母,出 ...
- 数据结构与算法(周鹏-未出版)-第六章 树-6.5 Huffman 树
6.5 Huffman 树 Huffman 树又称最优树,可以用来构造最优编码,用于信息传输.数据压缩等方面,是一类有着广泛应用的二叉树. 6.5.1 二叉编码树 在计算机系统中,符号数据在处理之前首 ...
随机推荐
- 第17月第26天 setImageForState变形
1. 关于UIButton,既可以采用setBackgroundImage 来设置底部图片,同时也可以采用 setImage方法: 两者还是有一定区别的: 首先setBackgroundImage, ...
- NULL、0、nullptr的区别
某些时候,我们需要将指针赋值为空指针,以防止野指针. 有人喜欢使用NULL作为空指针常量使用,例如:int* p = NULL;. 也有人直接使用0值作为空指针常量,例如:int* p = 0;. ...
- Java用System读取系统相关信息、环境变量——(六)
package Java_Test; public class System1 { public static void main(String[] args) { // TODO Auto-gene ...
- 《Joint Face Detection and Alignment using Multi-task Cascaded Convolutional Networks》
<Joint Face Detection and Alignment using Multi-task Cascaded Convolutional Networks> 论文主要的三个贡 ...
- Linux下clock计时函数学习
平时在Linux和Winows下都有编码的时候,移植代码的时候免不了发现一些问题.1. 你到底准不准?关于clock()计时函数首先是一段简单的测试代码,功能为测试从文本文件读取数据并赋值给向量最后打 ...
- 利用capability特征加强Linux系统安全【转】
转自:https://blog.csdn.net/fivedragon/article/details/676849 1.简介 UNIX是一种安全操作系统,它给普通用户尽可能低的权限,而把全部的系统权 ...
- GPIO接口解析【转】
本文提供了一个linux下访问GPIO的约定的概述. 这些调用使用gpio_* 命名前缀.没有别的调用会使用这个前缀或是相关的__gpio_*前缀. 转自:http://blog.163.com/w5 ...
- Linux内核中_IO,_IOR,_IOW,_IOWR宏的用法与解析【转】
转自:http://blog.csdn.net/hzn407487204/article/details/7995041 在驱动程序里, ioctl() 函数上传送的变量 cmd 是应用程序用于区别设 ...
- (常用)re模块
re模块(正则)#re:一些带有特殊含义的符号或者符号的组合#为什么要用re:一堆字符串中找到你所需要的内容,过滤规则是什么样,通过re模块功能来告诉计算机你的过滤规则#应用:在爬虫中最为常用:使用爬 ...
- Android系统信息(内存、cpu、sd卡、电量、版本)获取
Android系统信息(内存.cpu.sd卡.电量.版本)获取 /*APPInfo.java*/ public class AppInfo { private String appLable; pri ...