您的位置:首页 > 其它

Uva1354-天平难题

2017-05-08 00:14 633 查看
给出房间的宽度r和s个挂坠的重量wi,设计一个尽量宽(但宽度不能超过房间宽度r)的天平,挂着所有挂坠。 
天平由一些长度为1的木棍组成。木棍的每一端要么挂一个挂坠,要么挂另外一个木棍。如下图所示,设n和m分别是两端的总重量,要让天平平衡,必须满足n*a=m*b。



挂坠的宽度忽略不计,且不同的子天平可以相互重叠,下图所示如。



输入第一行为数据组数。每组数据前两行为房间宽度r和挂坠数目s (0 < r < 10,1<=s<=6)。以下s行为一个挂坠的重量wi(1<=wi<=1000)。输入保证不存在天平的宽度恰好在r-10^(-5)和r+10^(-5)(这样可以保证不会出现精度问题)。对于每组数据,输出最优天平的宽度。如果无解,输出-1。你的输出和标准答案的绝对误差不应超过10^(-8)。

样例输入:

1.7143 









5

样例输出:

1.7142857142857142

解题思路:回溯+枚举二叉树

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;

const int num = 6;
int s, vis[num];
double maxs=0.0;
double r, w[num], lenl[num], lenr[num];

int dfs(int cur) {
// 判断并输出结果
if (cur == s-1) {
for (int i = 0; i < s; i++) {
if (vis[i]) {
double tmp = lenl[i] + lenr[i];
if (r > tmp && tmp > maxs) maxs = tmp;
return 0;
}
}
}

// 回溯框架---合并子集
for (int i = 0; i < s; i++) {
if (!vis[i]) {
for (int j = 0; j < s; j++) {
if (i!=j && !vis[j]) {

vis[i]=1;
double tmp=w[j], a=w[j]/(w[i]+w[j]), b=1.0-a;
w[j]=w[i]+w[j];
double tmpl=lenl[j], tmpr=lenr[j];
lenl[j]=max(lenl[i]+a, lenl[j]-b);
lenr[j]=max(lenr[i]-a, lenr[j]+b);
dfs(cur+1);

//还原
lenl[j]=tmpl;
lenr[j]=tmpr;
w[j]=tmp;
vis[i]=0;
}
}
}
}

return 0;
}

// 主函数
int main() {
int i, A[num], L[num], R[num];
double sum=0.0, weight=0.0;

// 输入
cin >> r >> s;
for (int i = 0; i < s; i++) {
scanf("%lf", &w[i]);
if (weight < w[i]) weight = w[i];
}

// 验证是否有解
for (int i = 0; i < s; i++) {
if (w[i]!=weight) sum+=w[i];
}
if (sum < weight) {
cout << "-1" << endl;
return
4000
1;
}

// 回溯求解
memset(vis,0,sizeof(vis));
memset(lenl,0,sizeof(lenl));
memset(lenr,0,sizeof(lenr));
dfs(0);
printf("%.16f", maxs);

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: