UVa 1354 天平难题 (枚举二叉树)
Posted Neord
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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 }
以上是关于UVa 1354 天平难题 (枚举二叉树)的主要内容,如果未能解决你的问题,请参考以下文章