zoukankan      html  css  js  c++  java
  • Mobile Computing UVA

    回溯法+搜索对象的选取

    天平模型可看作一个只要有子树则左右子树必然全有的树,则枚举每个天平的实例(也就是每个集合)就是枚举所有可能的每棵树。

    每次选择当前集合的一个子集作为左子树,当前总集作为当前根,来创建树。

    通过dfs后续遍历树,在从最深处叶子返回到根时,存储每个当前总集的根到最左端和最右端的距离;

    由递推式 当前根到最左端/右端距离=其左子树到最左端+根到左子树       右则是:右子树到最右端+根到右子树;

    因为天平可以重叠,所以要考虑一个天平a的 左子天平al的到其右子树alr的长度减掉它到al的那一段还比右侧正常情况长!左侧同理

    并且如果天平已经访问过,则不再重复访问,进行回溯!具体的看代码注解。

    // 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) {}
    };
    
    const int maxn = 6;
    
    int n, vis[1<<maxn];
    double r, w[maxn], sum[1<<maxn];
    vector<Tree> tree[1<<maxn]; //每个子集都对应了一个 vector<tree> 容器,来存
    
    void dfs(int subset) {
      if(vis[subset]) return;    //不重复访问访问过的子集,因为这个dfs只记录每个subset作为根时 到其左右子树最左右叶子部分的长度,所以重复访问没有意义,完全一样!
      vis[subset] = true;        //
    
      bool have_children = false;
      for(int left = (subset-1)&subset; left; left = (left-1)&subset) {     //去left中所有与subset相同的元素。若不存在则退出循环
        have_children = true;//如果存在,则将子集标志致真                //就是遍历集合的所有子集,真实没想到还能这样写!但是这样写会重复不少次,比如11000001这个集合。因为前边的1捡不到,所以会使包含头尾元素的子集dfs调用很多次
    
        int right = subset^left;//右子集为左子集相对总集的补集!(这个我会!)
        double d1 = sum[right] / sum[subset];//d1为左边的天平杆的长度
        double d2 = sum[left] / sum[subset];//d2为右边的
    
        dfs(left); dfs(right);//然后递归求left right子树的。(只要没走到叶子结点时一定会走到这一步,即这一步的下一步一定是执行完 该子树的操作后进行。
    
        for(int i = 0; i < tree[left].size(); i++)//对于当前left,right 已经进行判断过的结点或者叶子结点才用(其实这一点是必然的,这一步是在对子树dfs之后的,算是后序遍历)
          for(int j = 0; j < tree[right].size(); j++) {
            Tree t;     //注意接下来的两个max()函数!!并不是想求每个左右子树中的末端结点到 其自己根的长度中的最长的!而是只用来判断每个左右
            t.L = max(tree[left][i].L + d1, tree[right][j].L - d2);//后边那个的那部分来处理重叠情况,就是如果右子树right的子树太长了,比在减去d2后都超过比左边leift向左生长的子树长度了
            t.R = max(tree[right][j].R + d2, tree[left][i].R - d1);//同理,处理left的有子树太长    //这一步判断想的是真的细。
            if(t.L + t.R < r) tree[subset].push_back(t);//如果符合条件,记录当前集合作为某层根结点(只要符合条件的全要!,并不是存当前最大)
          }
      }
    
      if(!have_children) tree[subset].push_back(Tree());//递归到叶子结点时,为该叶子结点创建Tree(都是0,逻辑上一个叶子结点不应该有左右子树的天平杆)来记录他从root到最左右天平长度
    }
    
    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];//sum[0]-sum[n] 为w[j]每个集合重量
        }
    
        int root = (1<<n)-1;    //设根为全集
        memset(vis, 0, sizeof(vis));
        dfs(root);//通过dfs
    
        double ans = -1;
        for(int i = 0; i < tree[root].size(); i++)
          ans = max(ans, tree[root][i].L + tree[root][i].R);//从tree[root]中筛选哪种 左右子集选择最大
        printf("%.10lf
    ", ans);
      }
      return 0;
    }
  • 相关阅读:
    SNMP概述–运维必知的协议基础
    关于多线程情况下Net-SNMP v3 版本导致进程假死情况的跟踪与分析
    关于snmp octet string和普通string问题
    SVN状态说明
    SNMP mib文件说明
    Linux之 proc文件系统
    django .all .values .value_list 数据库获取数据
    Django form验证
    JSONP实现
    iframe和form表单实现ajax请求上传数据
  • 原文地址:https://www.cnblogs.com/worldcreator-zh/p/10769859.html
Copyright © 2011-2022 走看看