题意:给一堆石头和长度为1的木棍,木棍端点可以挂石头或木棍,组成天平树。求不超过给定长度的最长天平。
解决:暴力枚举:每次在现有的石块/天平节点中任取两个,组成新的天平节点,直到取光;算出这颗天平树的平衡条件,得到天平长度。
代码:
//Mobile Computing
//My solution. Yhq
#include<iostream>
#include<cstring>
#include<iomanip>
#include<vector>
#include<queue>
using namespace std;
struct node;
void reset();
void dfs(int);
void calculate();
void print_tree(node);
double maxw;
double inf=1, sup=-1;
double width;
int num;
double stone[10];
bool vis[10];
vector<node*> nodes;
int main() {
//freopen("MC.txt","w",stdout);
int test;
cin>>test;
while (test--) {
reset();
cin>>width>>num;
for (int i=1; i<=num; ++i) cin>>stone[i];
dfs(0);
if (maxw<0) cout<<maxw<<endl;
else cout<<setiosflags(ios::fixed)<<setprecision(10)<<maxw<<endl;
}
return 0;
}
struct node{
double lw, rw, ll, rl, pos; //left weight; right weight; left length; right length; position.
node *left, *right;
node(): lw(0), rw(0), ll(0), rl(0), pos(0), left(NULL), right(NULL) {}
};
void reset() {
memset(vis,false,sizeof(vis));
memset(stone,0,sizeof(stone));
nodes.clear();
maxw=-1;
}
void calculate(node root) {
//print_tree(root);
root.ll=root.rw/(root.rw+root.lw);
root.rl=root.lw/(root.rw+root.lw);
if (root.pos-root.ll < inf) inf=root.pos-root.ll;
if (root.pos+root.rl > sup) sup=root.pos+root.rl;
if (root.left) {
root.left->pos=root.pos-root.ll;
calculate(*(root.left));
}
if (root.right) {
root.right->pos=root.pos+root.rl;
calculate(*(root.right));
}
}
void dfs (int depth) {
if (depth==num-1) {
nodes[0]->pos=0;
inf=1, sup=-1;
calculate(*nodes[0]);
if (sup-inf<width && sup-inf>maxw) maxw=sup-inf;
return;
}
for (int i=1; i<=num+5; ++i) {
if (i<=num && !vis[i]) {
vis[i]=true;
int stone1=stone[i];
for (int j=1; j<=num+5; ++j) {
if (j<=num && !vis[j]) {
vis[j]=true;
int stone2=stone[j];
node* newnode=new node;
newnode->lw=stone1;
newnode->rw=stone2;
nodes.push_back(newnode);
dfs(depth+1);
nodes.pop_back();
delete newnode;
vis[j]=false;
}
else if (j>num && j-num<=nodes.size()) {
vector<node*> tempvec=nodes;
node *ptr=nodes[j-num-1];
nodes.erase(nodes.begin()+j-num-1);
node* newnode=new node;
newnode->lw=stone1;
newnode->rw=ptr->lw+ptr->rw;
newnode->right=ptr;
nodes.push_back(newnode);
dfs(depth+1);
delete newnode;
nodes=tempvec;
}
}
vis[i]=false;
}
else if (i>num && i-num<=nodes.size()) {
vector<node*> tempvec=nodes;
node *ptr1=nodes[i-num-1];
nodes.erase(nodes.begin()+i-num-1);
for (int j=1; j<=num+5; ++j) {
if (j<=num && !vis[j]) {
int stone2=stone[j];
vis[j]=true;
node* newnode = new node;
newnode->lw=ptr1->lw+ptr1->rw;
newnode->rw=stone2;
newnode->left=ptr1;
nodes.push_back(newnode);
dfs(depth+1);
nodes.pop_back();
delete newnode;
vis[j]=false;
}
else if (j>num && j-num<=nodes.size()) {
node* ptr2=nodes[j-num-1];
vector<node*> tempvec2=nodes;
nodes.erase(nodes.begin()+j-num-1);
node* newnode = new node;
newnode->lw = ptr1->lw+ptr1->rw;
newnode->rw = ptr2->lw+ptr2->rw;
newnode->left = ptr1;
newnode->right = ptr2;
nodes.push_back(newnode);
dfs(depth+1);
delete newnode;
nodes=tempvec2;
}
}
nodes=tempvec;
}
}
}
//debug
void print_tree(node root) {
queue<node> que;
que.push(root);
cout<<"BFS Tree: "<<endl;
while (!que.empty()) {
node tmp=que.front();
que.pop();
cout<<"lw: "<<tmp.lw<<" "<<"rw:"<<tmp.rw<<endl;
if (tmp.left) que.push(*(tmp.left));
if (tmp.right) que.push(*(tmp.right));
}
}