例题7-7 UVA 1354 Mobile Computing (搜索+二叉树(类哈夫曼树))

12 篇文章 0 订阅
12 篇文章 0 订阅

思路:

想一想就可以知道,一个结点要么有两个儿子,要么没儿子。

那么这就很像哈夫曼树,因此我们可以枚举所有的哈夫曼树(任意枚举两个不同的结点来合并)

然后从根结点开始遍历二叉树,在遍历的同时,来枚举左边 和右边的最大值。

然后R-L 便是这个二叉树的宽度。

更新一下答案即可!

有一个小小的坑把,没注意到:

就是只有一个砝码的时候,答案应该是0 不是-1.

想一想还是很实际的:

只有一个砝码,直接拿个绳子吊起来就行了,题目中说 不考虑砝码的宽度,那么不就是0了吗!!

详细见代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cmath>
#include <cstdlib>
#define Siz(x) (int)x.size()
using namespace std;
const double eps = 1e-10;
int dcmp(double a,double b){
    if (fabs(a-b) < eps) return 0;
    if (a < b) return -1;
    return 1;
}
struct Node{
    int v;
    int ban;
    Node* left;
    Node* right;
    Node(int v = 0,int ban = 0):v(v),ban(ban){
        left = right = NULL;
    }
};
int T, n;
double r;
double L,R,ans;
vector<Node*>v;
void dfs2(Node* cur,double dis){
    if (cur->left == NULL || cur->right == NULL) return;
    int lv = cur->left->v;
    int rv = cur->right->v;
    double k = rv*1.0/lv;
    double a = k/(1+k);
    double b = 1.0/(1+k);
    double nl = dis - a;
    double nr = dis + b;
    if (dcmp(L,nl) == 1) L = nl;
    if (dcmp(R,nr) == -1) R = nr;
    dfs2(cur->left,nl);
    dfs2(cur->right,nr);
}

void dfs(int siz){
//    printf("%d\n",siz);
    if(siz > 1){
        for (int i = 0; i < Siz(v); ++i){
            for (int j = 0; j < i; ++j){
                if (i != j){
//                    printf("%d %d\n",i,j);
                    Node* ii = v[i];
                    Node* jj = v[j];
                    v.erase(v.begin()+i);
                    v.erase(v.begin()+j);
//                    puts("hahahaha");
                    Node* kk = new Node(ii->v + jj->v);
                    kk->ban = 1;
                    kk->left = new Node();
                    kk->right = new Node();
                    kk->left = ii;
                    kk->right = jj;
                    v.push_back(kk);
                    dfs(siz-1);
                    v.pop_back();
                    kk = new Node(ii->v + jj->v);
                    kk->ban = 1;
                    kk->left = new Node();
                    kk->right = new Node();
                    kk->left = jj;
                    kk->right = ii;
                    v.push_back(kk);
                    dfs(siz-1);
                    v.pop_back();
                    if (j >= Siz(v))v.push_back(jj);
                    else v.insert(v.begin()+j,jj);
                    if (i >= Siz(v))v.push_back(ii);
                    else v.insert(v.begin()+i,ii);
                }
            }
        }
    }
    else {
//        puts("ahahah");
        Node* root = new Node();
        root = *(v.begin());
//        printf("%d\n",root->v);
        L = 1e18;
        R = -1e18;
        dfs2(root,0);
        double nnr = R-L;
        if (dcmp(nnr,r) != 1){
//            ans = max(ans,nnr);
            if (dcmp(ans,nnr) == -1) ans = nnr;
        }
    }
}
int main(){
    scanf("%d",&T);
    while(T--){
        v.clear();
        ans = -1e18;
        scanf("%lf%d",&r,&n);
        for (int i = 0; i < n; ++i) {
            int vv;
            scanf("%d",&vv);
            v.push_back(new Node(vv,0));
        }
        dfs((int)v.size());
        if(n == 1) puts("0"); /// 要格外注意,一个砝码的时候 宽度是0,不是-1.
        else if (ans == -1e18) puts("-1");
        else printf("%.16f\n",ans);
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值