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

题意:

分析:

其实刚看到这题的时候觉得很难, 以至于结束了第七章然后去做了一遍第六章树的部分。现在再做这题觉得思路并不是太难,因为总共就只有六个结点,那么只要枚举二叉树然后算出天平然后再从叶子往上推就能得出这棵树的宽度。这题我觉得主要难点是如何去枚举二叉树,其实这就是回溯法的核心。先去dfs选这个作为结点的, 然后还原, 再做不选的dfs, 这样就能没有遗漏(但会有重复)地枚举二叉树了。

这题还有个细节是一个天平中,左子树的右长度可能会超过天平右臂 + 右子树的长度, 如下图

那么就不能单纯地看右臂+右子树的长度了, 要取一个最大值作为这个天平的最右, 反过来的左边也是一样的。

 1 #include <cstdio>
 2 #include <iostream>
 3 #include <cstring>
 4 using namespace std;
 5 struct Tree{
 6     double L, R;
 7     Tree(int _L = 0, int _R = 0):L(_L), R(_R){}
 8 };
 9 Tree tree[1<<6];
10 int w[1<<6], vis[1<<6];
11
12 int n, ind;
13 double room, maxw;
14
15 int dfs(int dep){
16     if(dep == n - 1){// 递归边界
17         if(tree[ind].L + tree[ind].R <= room)
18             maxw = max(maxw, tree[ind].L + tree[ind].R);
19     }
20     for(int i = 1; i <= ind; i++){
21         if(!vis[i]){
22             for(int j = 1; j <= ind; j++){
23                 if(i != j && !vis[j]){
24
25                     vis[i] = vis[j] = 1;//建树
26                     w[++ind] = w[i] + w[j];
27
28                     int wl = w[i], wr = w[j];
29                     //   a  |  b
30                     //  ----------
31                     //  |        |
32                     //  wl      wr
33
34                     double a = (double)wr/(wl + wr);
35                     double b = 1.0 - a;
36
37                     tree[ind].R = max(b + tree[j].R, tree[i].R - a);//比较着取最大值,
38                     tree[ind].L = max(a + tree[i].L, tree[j].L - b);
39
40                     dfs(dep + 1);
41
42                     vis[i] = vis[j] = vis[ind] = 0;//还原
43                     tree[ind].R =  tree[ind].L = 0;
44                     --ind;
45                 }
46             }
47         }
48     }
49 }
50 int main(){
51     int T;
52     scanf("%d", &T);
53     while(T--){
54         memset(tree,0,sizeof(tree));
55         ind = 0;//秤砣数组下标
56         scanf("%lf", &room);
57         scanf("%d", &n);
58         for(int i = 1; i <= n;i++){
59             scanf("%d", &w[i]);
60             ind++;
61         }
62         maxw = -1;
63         memset(vis,0,sizeof(vis));
64         dfs(0);
65         if(maxw == -1)
66             printf("-1\n");
67         else
68         printf("%.16f\n", maxw);
69     }
70     return 0;
71 }
时间: 2024-10-06 22:09:28

UVa 1354 天平难题 (枚举二叉树)的相关文章

UVa 1354 天平难题

首先呈现刘汝佳的高级代码 // 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 point Tree():L(0),R(0) {} }; co

UVA 1354 Mobile Computing(天平难题,枚举子集,递归,好题*)

1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 5 /** 6 思路:在每一个根节点枚举左右子树 7 8 学习: 9 (1)枚举子集的方法 例如 枚举 s = 100101 的子集 10 for(int l = (s-1)&s , l > 0 ; l = (l-1) & s){ 11 int r = s ^ l; 12 (2)思考:如何表示 左边距离 右边距离 . 该点的

uva1354 天平难题 解题报告

uva1354 天平难题.主要有 回溯法,二叉树模拟. 当然,这道题也有很多剪枝,但是这个用二叉树性质模拟的数组应该过了,这样写,这道题,完全就足够了. 原题目链接:https://uva.onlinejudge.org/external/13/1354.pdf 题目大意: 就是首先给你一个房间的宽度r,之后有s个挂坠,第i个挂坠的重量是wi,设计一个尽量宽,但是不能宽过房间.的天平.当然会有好几组这样的数据. 这些天平棍的长度都为1,天平棍要么挂 挂坠,要么就继续挂木棍设挂的木棍必须要让天平平

uva 1354 Mobile Computing ——yhx

1 #include<cstdio> 2 #include<cmath> 3 #include<cstring> 4 struct node 5 { 6 int fat,lson,rson; 7 double wei; 8 }tree[500]; 9 double w[10],lim,ans; 10 int n; 11 double max(double x,double y) 12 { 13 return x>y?x:y; 14 } 15 void calc_s

Uva 1354 Mobile Computing

题目链接 题意: 在一个宽为r 的房间里, 有s个砝码, 每个天平的一端要么挂砝码, 要么挂另一个天平, 并且每个天平要保持平衡. 求使得所有砝码都放在天平上, 且总宽度不超过房间宽度的最大值. 思路: 每个节点只能有两个子节点, 这是一棵二叉树的形式. 通过枚举二叉树的形态, 再枚举每一个叶子节点所放砝码, 最后再计算每个方案的宽度并计算答案. 每增加一个天平, 那么可以放砝码数 + 1. note: 坑在0的输出了, 用primtf("%.9lf\n", 0)输出来的是0  用0.

UVa1354 Mobile Computing (枚举二叉树)

链接:http://acm.hust.edu.cn/vjudge/problem/41537分析:二进制法枚举二叉树.用n位二进制位代表n个元素,第i位为1代表集合中包含第i个元素,否则不包含.从右往左依次表示第0,1,2,3...n-1号元素,sum表示包含集合中的元素时的总重量,tree[subset]表示包含集合中的元素时天平合法的L和R,vis表示当前子集是否已经被枚举过避免重复枚举.然后就是dfs递归枚举子集,枚举左子树的集合剩下的就是右子树,然后继续递归枚举,枚举到叶子结点或vis为

UVa 725 Division --- 简单枚举

题目链接: https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=666 /* UVa 725 Division --- 简单枚举 */ #include <cstdio> #include <cstring> bool used[10]; /* 判断传进来的两个数是否满足条件 */ bool judge(int a, i

uva Fire Station(FLODY+枚举)(挺不错的简单题)

消防站 题目链接:Click Here~ 题意分析: 就是给你f个消防站,n个路口.要你求出在已有消防站的基础上在n个路口的哪个路口上在建立一个消防站,使得n个路口的到离自己最近的消防站最近的距离中最大的一个值最小.即:求n个最近路口中最大的一个,使其改最大值最小.详细的要求自己看题目吧~ 算法分析: 因为,是n个路口到每个消防站的距离.所以,我们可以想到先用一次Flody算法.把每两点的最近距离给算出来.之后在枚举N个路口,进行判断比较得出答案. #include <iostream> #i

UVA 10574 - Counting Rectangles(枚举+计数)

10574 - Counting Rectangles 题目链接 题意:给定一些点,求能够成几个矩形 思路:先把点按x排序,再按y排序,然后用O(n^2)的方法找出每条垂直x轴的边,保存这些边两点的y坐标y1, y2.之后把这些边按y1排序,再按y2排序,用O(n)的方法找出有几个连续的y1, y2都相等,那么这些边两两是能构成矩形的,为C2cnt种,然后累加起来就是答案 代码: #include <stdio.h> #include <string.h> #include <