题意:给出房间宽度r和s个挂坠的重量wi。设计一个尽量宽(但宽度不能超过房间宽度r)的天平,挂着所有挂坠。天平由一些长度为1的木棍组成。木棍的每一端要么挂一个挂坠,要么挂另一个木棍,设n和m分别是两端挂的总重量,要让天平平衡,必须满足n*a=m*b。(0<r<10,1s6)。输出和标准答案的绝对误差不应该超过

分析:好了数值很小,可以暴力,问题是怎么枚举二叉树。这是本题的难点,很多人第一次做这种类型的题目时,都不知道怎么下手,当然我也是,考虑很久,也写不出枚举二叉树算法,看过解析才知道原来可以这么简单,才知道自己对二叉树的理解还是欠缺了。二叉树的核心在于结点可以组成节点。

下面以一个例子来说明:

4个挂坠,每个挂坠重量分别为1,2,3,5。房间宽度为1.7143。

3                                                                                                                                                                                                0.666|0.333                                                                                                                                                                                      -------------------                                                                                                                                                                                    |                      |                                                                                                                                                                                   1                     2

先将第一个节点和第二个节点组成一个节点,重量为3,左边宽度为0.6666,右边为0.3333,增加到节点列表中,节点列表为1,2,3,5,3。然后继续找下一层,找另外两个没找过的节点为3,5,组成节点,重量为8,增加到节点列表中,当前节点列表为1,2,3,5,3,8,访问列表为0,0,0,0,1,1。0表示访问过。所以继续下一层,然后就剩下组合节点3和8了,取3左边的长度为0.666,8右边的长度为0.375。相加为1.041再加上1就是2.041,超过房间宽度,那么这种情况就不符合,继续循环这次是8和3,取8的左边为0.625取3的右边0.3,还是超过,不符合,没有可访问节点,回溯。回溯到第二层,目前循环到刚刚是3和5,5访问过不符合,下面就继续访问节点4也就是重量3,是组合节点有其左右长度,分别为0.666和0.333,一开始是3和3取也就是节点2和节点4,取2节点左边长度为0,4节点右边长度为0.333,总长度为1.333,将节点6重量为6添加到节点列表中,节点列表为1,2,3,5,3,6,节点6左右长度分别是0.5和0.8333。可以进行下一层,访问列表为0,0,0,1,0,1。可访问的节点是3和6,然后取3的左边和6的右边,不符合,循环,取6的左边和3的右边为0.5+1<1.7041,符合条件,达到顶层,退出和当前最大比较。回溯下一个。以此类推可以访问过所有节点组成的所有二叉树。

代码部分:

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include<iostream>
using namespace std;
const int maxn = 20;
double lw[maxn], rw[maxn], r; int w[maxn], vis[maxn]; int indexw = 0; int n; double ans;
void dfs(int layer) {if (layer == n)return;for (int i = 0; i < maxn; i++) {if (vis[i]) {for (int j = 0; j < maxn; j++) {if (i != j && vis[j]) {double L = max(lw[i], lw[j] - 1); double R = max(rw[j], rw[i] - 1);//防止右边的节点的左长度超过左边节点的左长度,同理右也是if (L + R + 1 < r) {//判断是否小于房间长度if (layer == n - 1)ans = max(ans, L + R + 1);vis[i] = vis[j] = 0;//置为访问过int id = indexw++;vis[id] = 1;//新节点置为可访问w[id] = w[i] + w[j];//新节点重量为两节点之和lw[id] = w[j]*1.0 / w[id] + L;//不能忘记加上之前的右边长度rw[id] = w[i]*1.0 / w[id] + R;dfs(layer + 1);vis[i] = vis[j] = 1;vis[--indexw] = 0;//新节点要置为不可访问!}}}}}
}
int main() {int kase;cin >> kase;while (kase-- > 0) {indexw = 0; ans = -1;memset(vis, 0, sizeof(w));memset(lw, 0, sizeof(lw));memset(rw, 0, sizeof(rw));cin >>r>> n;for (int i = 0; i < n; i++) { cin >> w[i]; vis[indexw++] = 1; }if (n == 1) { printf("0.0000000000\n"); continue; }dfs(1);printf("%.10lf\n", ans);}return 0;
}

老师的代码是玄学(表示学不来)

// UVa1354 Mobile Computing
// Rujia Liu
#include<cstdio>
#include<cstring>
#include<vector>
using namespace std;
struct Tree {double L, R; // distance from the root to the leftmost/rightmost pointTree():L(0),R(0) {}
};
const int maxn = 6;
int n, vis[1<<maxn];
double r, w[maxn], sum[1<<maxn];
vector<Tree> tree[1<<maxn];
void dfs(int subset) {if(vis[subset]) return;vis[subset] = true;bool have_children = false;for(int left = (subset-1)&subset; left; left = (left-1)&subset) {have_children = true;int right = subset^left;double d1 = sum[right] / sum[subset];double d2 = sum[left] / sum[subset];dfs(left); dfs(right);for(int i = 0; i < tree[left].size(); i++)for(int j = 0; 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);for(int i = 0; i < n; i++) scanf("%lf", &w[i]);for(int i = 0; i < (1<<n); i++) {sum[i] = 0;tree[i].clear();for(int j = 0; j < n; j++)if(i & (1<<j)) sum[i] += w[j];}int root = (1<<n)-1;memset(vis, 0, sizeof(vis));dfs(root);double ans = -1;for(int i = 0; i < tree[root].size(); i++)ans = max(ans, tree[root][i].L + tree[root][i].R);printf("%.10lf\n", ans);}return 0;
}

他用的是二进制枚举子集,每次都取出左右子集,枚举集合的所有子集,最后进行子集判断,果然厉害。

UVA1354天平难题 枚举二叉树相关推荐

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

    题意:给出房间宽度 r 和 s 个挂坠的重量 wi,设计一个尽量宽的天平,挂着所有挂坠.天平由一些长度为 1 的木棍组成,木棍的每一端要么挂一个挂坠,要么挂另外一个木棍. 这题卡了很久,看了很多大神的 ...

  2. LA3403天平难题(4个DFS)

    题意:      给出房间的宽度r和每个吊坠的重量wi,设计一个尽量宽但宽度不能超过房间宽度的天平,挂着所有挂坠,每个天平的一段要么挂这一个吊坠,要么挂着另一个天平,每个天平的总长度是1,细节我给出题 ...

  3. LA3403 天平难题

    题意:      给出房间的宽度r和每个吊坠的重量wi,设计一个尽量宽但宽度不能超过房间宽度的天平,挂着所有挂坠,每个天平的一段要么挂这一个吊坠,要么挂着另一个天平,每个天平的总长度是1,细节我给出题 ...

  4. AcWing479.加分二叉树(区间DP)题解

    加分二叉树 题目传送门 题目描述 设一个n个节点的二叉树tree的中序遍历为(1,2,3,-,n),其中数字1,2,3,-,n为节点编号. 每个节点都有一个分数(均为正整数),记第i个节点的分数为di ...

  5. 面试必备:高频算法题汇总「图文解析 + 教学视频 + 范例代码」必问之 排序 + 二叉树 部分!

    排序 所谓排序算法,即通过特定的算法因式将一组或多组数据按照既定模式进行重新排序.这种新序列遵循着一定的规则,体现出一定的规律,因此,经处理后的数据便于筛选和计算,大大提高了计算效率. 对于排序: 我 ...

  6. 面试必备:高频算法题汇总「图文解析 + 教学视频 + 范例代码」必知必会 排序 + 二叉树 部分!

    排序 时光小说网 https://wap.youxs.org/ 所谓排序算法,即通过特定的算法因式将一组或多组数据按照既定模式进行重新排序.这种新序列遵循着一定的规则,体现出一定的规律,因此,经处理后 ...

  7. 算法作业1:遍历与枚举

    本文持续更新 Update date: 2021/10/6 算法系列文章 搜索算法:遍历与枚举 分治算法:修身,齐家,编算法! 笔记目录 什么是枚举? 什么时候用枚举? 机器学习中的枚举 特征选择(f ...

  8. 【计科二班】编程测试题解

    A.MinMax swap 我们假定两个序列中最大值为MAX,则无论如何交换,A或B序列中必有一个序列最大值为MAX. 则答案固定为MAX*max(A) 或 MAX*max(B).最小化max(A)或 ...

  9. 《算法竞赛入门经典(第2版)》——学习记录

    前言:   这里主要记录本人在学习紫书过程中充分理解过的题目的AC代码,便于以后回顾时查找代码和思路,毕竟看别人的真的有点难懂.此外,本书甚至是本书之外的相关知识学习也可能在此留下记录.   作为一只 ...

最新文章

  1. python3 subprocess_Python 3.4.3 subprocess.Popen获取命令输出而不管道?
  2. java 肌汉模式_设计模式之原型模式详解(附源代码)
  3. lisp标注界址点号_(IP服务年终大盘点第二期)协会理事单位湖北高韬律师事务所完成韩国商标注册优先审查...
  4. JavaScript之match()方法讲解
  5. 作者:熊赟,博士,复旦大学计算机科学技术学院副教授。
  6. Android 解析JSON
  7. 5G格局剧变!苹果高通和解,英特尔退票出局,华为独善其身
  8. VScode-Go can't load package: package .: no buildable Go source files in
  9. php mysql cpu使用率_Mysql CPU占用高的问题解决方法小结
  10. 怎么将两台计算机ping接通,小编教你手把手教你一根网线连接两台电脑实现数据传送...
  11. RFC 文档(1001-1500)
  12. vue element UI 学习总结笔记(十一)_vue中打印模板设置
  13. 18岁少年辍学组建黑客俱乐部 已覆盖62所学校
  14. 输入国家名按字典顺序进行排序
  15. 关于C++、C#实现EXCEL数据库批量导入数据库万行以上数据效率问题
  16. RelativeLayout.LayoutParams.addRule()方法
  17. 报错 | vue-router.esm.js?3423:2065 Uncaught (in promise) NavigationDuplicated: Avoided redundant navig
  18. eclipse反编译离线安装
  19. c 语言filter过滤方法,R语言日常笔记(1)filter函数
  20. 微信逆向分析(三)——逆向分析的实现思路

热门文章

  1. EventLoop 的启动
  2. 缓存-分布式锁-Redisson-读写锁补充
  3. (常用API)正则表达式切割练习
  4. 后台服务系统之Dubbo协议
  5. 数据库-分组语句及用法
  6. 开始使用Spring Cloud实战微服务
  7. smartupload 路径不存在_洞悉复杂金融场景,覆盖完备测试路径
  8. 第三章:系统困境之 忽略过去现在未来构成的时间系统
  9. Lindström–Gessel–Viennot lemma
  10. 跨主机使用 Rex-Ray volume - 每天5分钟玩转 Docker 容器技术(77)