UVA - 1354 Mobile Computing【这是我写过最认真的题解】 C++

题目:https://odzkskevi.qnssl.com/57f8af2fae951ced8a717f7384d90ed8?v=1532560185

题目大意:

(准备六级的我决定练一练英语阅读,所以翻译一下)

这里有一个神秘的星球叫Yaen,它的空间只有两个维度。这里有很多漂亮的石头在这个星球上,Yaen星人喜欢捡这些石头。他们把这些石头带回家,用很棒的移动装置来装饰他们的二维房间。

在他们的二维世界里,“移动装置”被递归地定义如下:

●一个绳子挂着一个石头,或者

●一根长度为1的杆的两端有两个移动装置;杆被一根绳子吊在亚移动装置的重心上;当这两个亚移动装置的重量分别是n和m,并且它们与重心的距离分别是a和b时,重心方程n × a = m × b。

举个例子,你有三块石头,它们的重量分别是1,1,2,这里有一些可能的移动装置和它们的宽度。

给你石头的重量和房间的宽度,你的任务是设计最长的移动装置满足一下两个条件:

•用完所有的石头

•移动装置的长度不能超过房间的宽度

你要忽略石头的宽度。

在某些情况下,两个挂在杆子两端的子移动装置可能会重叠(见右图)。这样的移动装置是可接受的。
这个例子的宽度是(1/3)+ 1 + (1/4)

 输入(就不逐字逐句翻译了):先输入n,有n组,每一组输入房间宽度,再输入有几个石头。再依次输入每个石头的重量。

输出:最大宽度。

思路:

一开始不太理解宽度怎么算的,然后问了一下队友。

每根木块的长度是1,所以(粗略地画了个图)

 就是这样子计算。(画画真好玩.jpg)

把天平转换成二叉树。比如第一个样例:

(灵魂画师)

这样看来,一个结点的左右宽度似乎等于它的左右宽度+它的子结点的左右宽度(不断递归)。

但是还有这样的情况。

 这个时候左边结点的右臂长度比右边结点的右臂长度还要长,所以我们每次算宽度时要取两种情况的最大值。

代码:

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
using namespace std;
struct Tree {
  double L, R;
  Tree():L(0),R(0) {}
}tree[1<<6];
int n, vis[1<<6];
double r, w[1<<6];
int cur;
double mmax;

void dfs(int d)
{
    if(d==n-1){
        if(tree[cur].L+tree[cur].R<=r){
            mmax=max(mmax,tree[cur].L+tree[cur].R);
            return;
        }
    }
    for(int i=1;i<=cur;i++){
        if(!vis[i]){
            for(int j=1;j<=cur;j++){
                if(!vis[j]&&i!=j){
                    vis[i]=vis[j]=1;
                    w[++cur]=w[i]+w[j];
                    int ll=w[i],rr=w[j];
                    double wl=rr*(1.0)/(ll+rr),wr=1-wl;
                    tree[cur].L=max(tree[i].L+wl,tree[j].L-wr);
                    tree[cur].R=max(tree[j].R+wr,tree[i].R-wl);
                    dfs(d+1);
                    vis[i]=vis[j]=vis[cur]=0;
                    tree[cur].L=tree[cur].R=0;
                    cur--;
                }
            }
        }
    }
}

int main()
{
    int T;
    cin>>T;
    while(T--){
        cur=0;
        memset(tree,0,sizeof(tree));
        memset(w,0,sizeof(w));
        scanf("%lf%d",&r,&n);
        for(int i=1;i<=n;i++){
            scanf("%lf",&w[i]);
            cur++;
        }
        mmax=-1;
        memset(vis,0,sizeof(vis));
        dfs(0);
        if(mmax==-1)cout<<mmax<<endl;
        else printf("%.16lf\n",mmax);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/zero_979/article/details/81222851
今日推荐