1354 Mobile Computing(暴力、二进制枚举、简直无情)

翘了3节课来A这道题,最后还超时了,也是蛮拼的。。

没做出来主要一个方面就是不会一个二进制数子集的枚举

这里上一下代码:

for(int S0 = S; S0; S0 = (S0 - 1) & S){

}

这里S0就是S的子集了~!

题目的思路就是枚举所有情况,注意记忆化【话说这题学到了不少】

#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
using namespace std;
//枚举二叉树的形状
const int maxn = 8;
const int maxd = (1 << 8);
int n;
double ww;
int w[maxn];
int sum[maxd];
int vis[maxd];
double ret;
struct Node{
    double l,r;
    Node(double ll,double rr):l(ll),r(rr){};
};
vector<Node>node[maxd];
void debug(int v){
    if(!v){puts(""); return;}
    debug(v / 2);
    printf("%d",v % 2);
}
bool judge(int S){
    for(int i = 0; i < n; i++)
        if(S == (1 << i))
            return true;
    return false;
}
void dfs(int S){      //枚举now的子集
    if(vis[S]) return;
    vis[S] = 1;
    if(judge(S)){
        node[S].push_back(Node(0,0));
        return;
    }
    //printf("%d\n",S);
    for(int S0 = S; S0; S0 = (S0 - 1) & S)if(S0 != S){
        int l = S0;
        int r = S0 ^ S;
        dfs(l); dfs(r);
        //枚举左右的子集
        for(int i = 0; i < node[l].size(); i++)
            for(int j = 0; j < node[r].size(); j++){
                double l1 = 1.0 * sum[r] / (sum[l] + sum[r]);
                double r1 = 1.0 * sum[l] / (sum[l] + sum[r]);
                double l2 = min(-l1 + node[l][i].l,r1 + node[r][j].l);
                double r2 = max(-l1 + node[l][i].r,r1 + node[r][j].r);
                //printf("[%d]: %.2f %.2f\n",S,l2,r2);
                node[S].push_back(Node(l2,r2));
            }
    }
    return;
}
int main(){
    int T;
    scanf("%d",&T);
    while(T--){
        scanf("%lf%d",&ww,&n);
        ret = -1;
        memset(vis,0,sizeof(vis));
        for(int i = 0; i < n; i++)
            scanf("%d",&w[i]);
        for(int i = 0; i < (1 << n); i++){
            sum[i] = 0;
            node[i].clear();
            for(int j = 0;j < n; j++){
                if(i & (1 << j)){
                    sum[i] += w[j];
                }
            }
        }
        int S = (1 << n) - 1;
        dfs(S);
        //printf("%d\n",node[S].size());
        for(int i = 0; i < node[S].size(); i++){
            double d = node[S][i].r - node[S][i].l;
            //printf("%.4f %.4f\n",node[S][i].r,node[S][i].l);
            if(d <= ww)
                ret = max(ret,d);
        }
        if(ret < 0) printf("-1\n");
        else
            printf("%.16f\n",ret);
    }
    return 0;
}
时间: 2024-07-30 10:09:40

1354 Mobile Computing(暴力、二进制枚举、简直无情)的相关文章

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)思考:如何表示 左边距离 右边距离 . 该点的

UVa 1354 Mobile Computing[暴力枚举]

**1354 Mobile Computing** There is a mysterious planet called Yaen, whose space is 2-dimensional. There are many beautiful stones on the planet, and the Yaen people love to collect them. They bring the stones back home and make nice mobile arts of th

UVa 1354 Mobile Computing | GOJ 1320 不加修饰的天平问题

传送门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 比赛的时候完全不知道怎么做,比赛完两天重新看一遍有点思路就是敲不出来(弱

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.

【二进制枚举+LCS】Card Hand Sorting

[二进制枚举+LCS]Card Hand Sorting 题目描述 When dealt cards in the card game Plump it is a good idea to start by sorting the cards in hand by suit and rank. The different suits should be grouped and the ranks should be sorted within each suit. But the order o

UVa 818 切断圆环链(dfs+二进制枚举)

https://vjudge.net/problem/UVA-818 题意:有n个圆环,其中有一些已经扣在了一起.现在需要打开尽量少的圆环,使得所有圆环可以组成一条链,例如,有5个圆环,1-2,2-3,4-5,则需要打开一个圆环,如圆环4,然   后用它穿过圆环3和圆环5后再次闭合4,就可以形成一条链:1-2-3-4-5. 思路:从n个圆环中任意选择圆环,这就是枚举子集.所以这道题目可以用二进制枚举来做. 那么如何判断当前打开圆环是可行的呢?在去除打开的圆环后需要判断: ①:每个圆环的分支数都必

UVa818 Cutting Chains (二进制枚举)

链接:http://vjudge.net/problem/35523 分析:links记录初始圆环链的情况,然后二进制枚举编号为0~n-1的圆环哪个被打开了,一个圆环最多一个前驱和一个后继,所以judge判断如果有一个未打开的圆环同时和2个以上的未打开圆环相连就一定不能形成链,剪去.circle判断剩下的未打开圆环是否形成环,以及若未成环那么有多少条单链links_num,注意最后成链不用按顺序比如1->2->3...这样.然后判断一下打开的圆环数够不够把links_num条单链扣成一条链,若

POJ 2436 二进制枚举+位运算

题意:给出n头牛的得病的种类情况,一共有m种病,要求找出最多有K种病的牛的数目: 思路:二进制枚举(得病处为1,否则为0,比如得了2 1两种病,代号就是011(十进制就是3)),首先枚举出1的个数等于k的二进制数,然后跟所有的牛的代号一一比较,符合的           +1,找出其中和最大的:就是转换2进制麻烦,用位运算就好实现了,但是位运算不是很明白含义,明白了再补充: 知识点: 3 & 2 = 2,相同为1,不同为0, 011 & 010 = 010:(怎么利用的这个特点不明白):