zoukankan      html  css  js  c++  java
  • UVa 1354 Mobile Computing | GOJ 1320 不加修饰的天平问题 (例题 7-7)

    传送门1(UVa): https://uva.onlinejudge.org/external/13/1354.pdf

    传送门2(GOJ): http://acm.gdufe.edu.cn/Problem/read/id/1320

    题意: 长度限制 r (1 < r < 10), 给 n (1 <= n <= 6) 个砝码,组成平衡(考虑重量和力臂)的天平,求天平最长能多长。

    2015个人选拔赛#6 1004

    比赛的时候完全不知道怎么做,比赛完两天重新看一遍有点思路就是敲不出来(弱渣...)=_=

    跟着Wenjun师兄的代码学了一下

    caodan的是最近在写多重for循环的时候总是在里层写错变量........找半天啊还好几个啊我这是怎么了................

    二进制枚举,类似线段树从底层一层一层处理

    #include <bits/stdc++.h>
    using namespace std;
    
    struct Tree{
        double l, r;
        Tree(double ll = 0.0, double rr = 0.0): l(ll), r(rr) {}
    };
    
    const int MAXN = 6;
    int n;
    bool vis[1<<MAXN]; // 是否访问过该子集
    double r, w[MAXN], sum[1<<MAXN];
    vector<Tree> tree[1<<MAXN]; // 保存各子集符合题意的解
    
    // 计算该子集包含的砝码个数,当为1时相当于到达二叉树结点
    int count(int x){
        int ans = 0;
        for(int i = 0; i < n; ++i)
            if(x & (1<<i)) ++ans;
        return ans;
    }
    
    void dfs(int subset){
        if(vis[subset]) return ;
        vis[subset] = true;
        if(count(subset) == 1){
            tree[subset].push_back(Tree());
            return;
        }
    
        //枚举该集合的所有子集
        for(int left = (subset-1) & subset; left; left = (left-1) & subset){
            int right = subset ^ left;
    
            //根据公式求当前左右集合对应力臂长度
            double leftlen = sum[right] / sum[subset];
            double rightlen = 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){
                    double ll = max(tree[left][i].l + leftlen, tree[right][j].l - rightlen);
                    double rr = max(tree[right][j].r + rightlen, tree[left][i].r - leftlen);
                    if(ll + rr < r) tree[subset].push_back(Tree(ll, rr));
                }
            }
        }
    }
    
    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>>j) & 1) sum[i] += w[j];  //二进制枚举各个子集的重量和
                }
            }
            int root = (1<<n) - 1; //整个天平
            memset(vis, false, 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);
            if(ans == -1) printf("-1
    ");
            else printf("%.15lf
    ", ans);
        }
        return 0;
    }
  • 相关阅读:
    二叉树的遍历
    十进制与m进制的相互转化
    【素数】Prime Distance
    【数论】Sumdiv(整数的唯一分解定理+约束和公式+递归求等比)
    【错位+组合】排列计数
    【扩展欧几里得】青蛙的约会
    【归并排序+逆序数】poj-2299 Ultra-QuickSort
    【模拟】Sandglass
    【位运算】高效解决n皇后问题
    Popular Cows
  • 原文地址:https://www.cnblogs.com/book-book/p/5335528.html
Copyright © 2011-2022 走看看