指针结点联合,即每个指针指向一个实际node,联合申请一个新node,并用一个新指针代表它;
#include<cstdio>
#include<cstring>
#include<cctype>
#include<queue>
#include <vector>
#include <iostream>
using namespace std;
const int maxn = 7;
typedef struct node *pointer;
struct node{
double weight,leftw,rightw,zhong;
node *left,*right;
node():left(NULL),right(NULL){}
};
int n;
double w[maxn],r;
double res=-1;
double cal_wei(pointer root,int floor){
if(root->left==NULL&&root->right==NULL){
root->leftw=root->rightw=0;
return root->weight;
}
root->leftw=cal_wei(root->left,floor+1);
root->rightw=cal_wei(root->right,floor+1);
return root->leftw+root->rightw;
}
double Min,Max;
void cal_posi(pointer root){
if(root->left==NULL&&root->right==NULL){
return ;
}
root->left->zhong=root->zhong-root->rightw/(root->rightw+root->leftw);
root->right->zhong=root->leftw/(root->rightw+root->leftw)+root->zhong;
Max=max(Max,root->right->zhong);
Min=min(Min,root->left->zhong);
cal_posi(root->left); cal_posi(root->right);
}
void dfs(int num,vector<pointer>& now){
if(num==1){
cal_wei(now[0],0);
now[0]->zhong=0;
Min=10000; Max=-10000;
cal_posi(now[0]);
if(Max-Min>=0&&Max-Min<=r){
res=max(res,Max-Min);
}
return ;
}
<pre name="code" class="html">//对本题而言,此解为朴素算法;
for(int i=0;i<num;i++)
for(int j=0;j<num;j++) if(i!=j){ //最坏复杂度分析, (6*5)*(5*4)*(4*3)*(3*2)*(2*1)*6*10*2 = 10368000;
vector<pointer> next; // 临时变量的位置特别重要;该句子放在循环外将导致每次没有消除dfs影响
pointer x=now[i],y=now[j];
for(int k=0;k<num;k++) if(k!=i&&k!=j) next.push_back(now[k]);
pointer temp=new node();
temp->weight=-1; temp->left=x; temp->right=y;
next.push_back(temp);
dfs(num-1,next);
}
}
int main()
{
int T;
scanf("%d",&T);
while(T--){
scanf("%lf %d",&r,&n);
vector<pointer> ans;
double x;
for(int i=1;i<=n;i++){
scanf("%lf",&x);
pointer temp=new node();
temp->weight=x;
ans.push_back(temp);
}
if(n==1) {
double t=0; printf("%.9lf\n",t); continue;
}
res=-1000;
dfs(n,ans);
if(res==-1000) printf("-1\n");
else printf("%.9lf\n",res);
}
return 0;
}
下面为高效算法;
用到子集的枚举技巧,node【i】里存的为所有子树姿态下的最优长度;
由于使用
#include <stdio.h>
#include <string.h>
#include <vector>
#define INF 0x3f3f3f3f
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
using namespace std;
const int N = 6;
const int MAXN = (1<<N);
int t, n, i, j, vis[MAXN];
double w[N], sumw[MAXN], r;
struct Node {
double l, r;
Node() {}
Node(double ll, double rr) {l = ll; r = rr;}
};
vector<Node> node[MAXN];
int bitcount(int x) {
if (x == 0) return 0;
return bitcount(x/2) + (x&1);
}
void dfs(int s) {
if (vis[s]) return;
vis[s] = 1;
if (bitcount(s) == 1) {
node[s].push_back(Node(0, 0));
return;
}
for (int l = (s - 1)&s ; l > 0; l = (l - 1)&s) { //非连续1(如11001)的子集枚举方式,循环量(2^(bitcount(s)-2))
int r = s^l;
dfs(l); dfs(r);
for (int i = 0; i < node[l].size(); i++) {
for (int j = 0; j < node[r].size(); j++) {
double ll =min(-sumw[r] / (sumw[l] + sumw[r]) + node[l][i].l,sumw[l] / (sumw[l] + sumw[r]) + node[r][j].l);
double rr =max(sumw[l] / (sumw[l] + sumw[r]) + node[r][j].r,-sumw[r] / (sumw[l] + sumw[r]) + node[l][i].r);
node[s].push_back(Node(ll, rr));
}
}
}
}
void solve() {
double ans = -1;
int s = (1<<n) - 1;
dfs(s); //printf("%d***\n",node[s].size()); node[s].size()代表所有可能的子树的左右最大值或最小值;
for (int i = 0; i < node[s].size(); i++) {
if (node[s][i].r - node[s][i].l < r) {
if (node[s][i].r - node[s][i].l > ans)
ans = node[s][i].r - node[s][i].l;
}
}
if (ans == -1) printf("-1\n");
else printf("%.10lf\n", ans);
}
int main() {
scanf("%d", &t);
while (t--) {
memset(vis, 0, sizeof(vis));
memset(node, 0, sizeof(node));
scanf("%lf%d", &r, &n);
for (i = 0; i < n; i++)
scanf("%lf", &w[i]);
for (i = 0; i < (1<<n); i++) {
sumw[i] = 0;
for (j = 0; j < n; j++) {
if (i&(1<<j))
sumw[i] += w[j];
}
} //计算每个子集的重量
solve();
}
return 0;
}