天平难题---Mobile Computing 枚举二叉树

版权声明:Nicolas https://blog.csdn.net/qq_42835910/article/details/86477829

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


图7-9 天平
例如,如果有3个重量分别为1, 1, 2的挂坠,有3种平衡的天平,如图7-10所示。

图7-10 3种平衡的天平
挂坠的宽度忽略不计,且不同的子天平可以相互重叠。如图7-11所示,宽度为(1/3)+1+(1/4)。
输入第一行为数据组数。每组数据前两行为房间宽度r和挂坠数目s(0<r<10,1≤s≤6)。以下s行每行为一个挂坠的重量Wi(1≤wi≤1000)。输入保证不存在天平的宽度恰好在r-10-5和r+10-5之间(这样可以保证不会出现精度问题)。对于每组数据,输出最优天平的宽度。如果无解,输出-1。你的输出和标准答案的绝对误差不应超过10-8。

枚举二叉树:由两节点组成一个新的节点,删掉原来的两个节点,将新生成的节点加原来的节点集S,如此循环往复,直到S只有一个节点。

#include<iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int maxn=13;
struct Tree{
	double r,l,w;//r,l分别为树两个分叉的左右距离 
}t[maxn];
double r,res;
int s;
bool use[maxn]; 
void binTree(int cur){
	for(int i=0;i<cur;i++){
		if(use[i]){//左节点 
			for(int j=0;j<cur;j++){
				if(j!=i && use[j]){//右节点 
					//左节点的r长度可能大于右边节点的r长度,两者的参考系相差一个杠杆的长度1
					double R=max(t[i].r-1,t[j].r),L=max(t[i].l,t[j].l-1);
					if(R+L+1<r) { 
						if(cur==2*s-2) {
							res=max(R+L+1,res);
							return;
						} 
						use[i]=use[j]=false;
						use[cur]=true;
						t[cur].w=t[i].w+t[j].w;
						t[cur].l=t[j].w*1.0/t[cur].w+L;//加上两个节点的最大左值 
						t[cur].r=t[i].w*1.0/t[cur].w+R; 
						binTree(cur+1);
						use[j]=use[i]=true;//恢复使用。					 
						use[cur]=false;					
					}					
				}
			}
		}
	} 
}

int main( ) {
	int n,cnt;
	cin>>n;
	while(n--){
		cin>>r>>s;
		cnt=0,res=-1;
		memset(t,0,sizeof(t));
		for(int i=0;i<s;i++){
			cin>>t[i].w;
			use[cnt++]=true;//标记能够使用 
		}	
		if (s == 1) {cout<<"0.0000000000\n"; continue;}			
		binTree(cnt);		
		printf("%.10lf\n",res);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_42835910/article/details/86477829
今日推荐