1 条题解
-
0
分析:
该问题本质上是一个组合优化问题,需要将给定重量的石头组合成满足力矩平衡条件的悬挂结构,并最大化其宽度。关键约束是: 1.必须使用所有石头
2.总宽度必须小于房间宽度
3.悬挂结构需满足力矩平衡条件 n·a = m·b(n,m 为子结构重量,a,b 为到重心距离)
算法核心原理
状态表示:使用位掩码(二进制数)表示石头的子集,例如 110 表示选择第 1 和第 2 块石头(从 0 开始计数)sum[subset] 存储子集 subset 中所有石头的总重量tree[subset] 存储子集 subset 能形成的所有合法悬挂结构的左右端点坐标
力矩平衡原理: 当左右子结构重量为 sum[left] 和 sum[right] 时,根据 sum[left]·a = sum[right]·b 且 a + b = 1(杆子长度为 1),可解得: 左子结构到重心距离 a = sum[right] / (sum[left] + sum[right]) 右子结构到重心距离 b = sum[left] / (sum[left] + sum[right])
宽度计算:悬挂结构的宽度由左右端点坐标差决定,即 right - left。合并左右子结构时,需考虑坐标偏移:左子结构向右移动 a,右子结构向左移动 b
算法步骤详解
1.输入处理与初始化: 读取数据集数量 T 和每个数据集的房间宽度 r、石头数量 n 及重量 w[i] 预处理每个子集的总重量 sum[subset],通过位运算遍历所有可能的子集
2.深度优先搜索(DFS)处理子集
关键步骤解析
1.子集枚举:使用 (subset - 1) & subset 高效枚举所有非空真子集,避免重复计算
2.力矩平衡计算:根据左右子结构重量比,计算各自到重心的距离
3.坐标合并:将左右子结构的坐标按距离偏移后,取边界最大值作为新结构的边界
4.合法性检查:确保合并后的宽度(t.l + t.r)小于房间宽度 r
5.结果计算: 遍历全集(所有石头)的所有合法悬挂结构,找到最大宽度
c++代码:
#include <iostream> #include <cstdio> #include <algorithm> #include <cstring> #include <vector> using namespace std; const int N=6; double r,sum[1<<N]; int n,w[N],T,vis[1<<N]; struct node{ double l,r; int ls,rs; node():l(0),r(0){} }; vector<node> tree[1<<N]; void dfs(int subset){//printf("dfs %d\n",subset); if(vis[subset]) return; vis[subset]=1; int child=0; for(int left=(subset-1)⊂left;left=(left-1)&subset){ child=1; int right=left^subset; dfs(left);dfs(right); double dl=sum[right]/sum[subset],dr=sum[left]/sum[subset]; for(int i=0;i<tree[left].size();i++) for(int j=0;j<tree[right].size();j++){ node t; t.l=max(tree[left][i].l+dl,tree[right][j].l-dr); t.r=max(tree[left][i].r-dl,tree[right][j].r+dr); if(t.l+t.r<r) tree[subset].push_back(t); } } if(!child) tree[subset].push_back(node());} int main(int argc, const char * argv[]) { scanf("%d",&T); while(T--){ scanf("%lf%d",&r,&n); for(int i=0;i<n;i++) scanf("%d",&w[i]); for(int i=0;i<(1<<n);i++){ sum[i]=vis[i]=0; tree[i].clear(); for(int j=0;j<n;j++) if(i&(1<<j)) sum[i]+=w[j]; } //for(int i=0;i<(1<<n);i++) printf("sum %d\n",sum[i]); int root=(1<<n)-1; dfs(root); double ans=-1; for(int i=0;i<tree[root].size();i++) ans=max(ans,tree[root][i].l+tree[root][i].r); printf("%.10f\n",ans); } return 0; }
- 1
信息
- ID
- 1743
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 4
- 已通过
- 1
- 上传者