专栏文章
题解:P7966 [COCI 2021/2022 #2] Hiperkocka
P7966题解参与者 1已保存评论 0
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 0 条
- 当前快照
- 1 份
- 快照标识符
- @mioxrm2y
- 此快照首次捕获于
- 2025/12/03 02:53 3 个月前
- 此快照最后确认于
- 2025/12/03 02:53 3 个月前
首先相信大家都发现了得满分要求每条边都被选入某棵树。
从菊花入手,此时等价于选出 个数使得他们两两之间相差至少两个二进制位。只需要选出所有 为偶数的数即可。
再考虑一般情况,换个角度理解题意,就是对于每条边 能找出它是哪棵树的哪条边。
尝试将这个定位逻辑简单化,那么由 和 得出的一个简单信息是 与 在哪一位不同,设为 ,那么我们可以规定它被定位到某棵树的第 条边上。
这也就是给 的每条边赋一个互不相同的 至 的边权(顺序随意),要求结果中每个 的相邻两点间相差的位就是边上的边权,即对于每个 有 ,其中 为所赋的边权。
于是此时我们只用确定 整个 序列就确定了。只需考虑怎么给每个 赋值。
考虑什么时候两棵树的两条边会冲突。
那么若 和 都含有边 ,则 在 和 的边权必然相同(为 ),也即它们是 上的同一条边。
我们将树按从根向叶子的方向定向,则若 在 和 中的方向相同,可以倒推出 和 的根节点权值相同,矛盾。
因此只有当 在 中是 而在 中是 时有可能冲突,此时可以推出 和 的根节点的权值恰相差一个二进制位 。
于是沿用菊花的做法,令每个根的节点都是 为偶数的数即可。
代码 500B。
CPP#include <bits/stdc++.h>
#define For(i,a,b) for(int i=a;i<=b;i++)
#define Rev(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
constexpr int N=55;
int n,a[N],cnt; vector<int> to[N];
void dfs(int u,int pa) { for(int v:to[u]) if(v!=pa) a[v]=a[u]^(1<<(cnt++)), dfs(v,u); }
int main(){
cin>>n; For(i,1,n) { int x,y; cin>>x>>y; to[x].push_back(y); to[y].push_back(x); }
dfs(0,-1); cout<<(1<<(n-1))<<'\n';
For(s,0,(1<<n)-1) if(__builtin_parity(s)) For(i,0,n) cout<<(s^a[i])<<" \n"[i==n];
return 0;
}
相关推荐
评论
共 0 条评论,欢迎与作者交流。
正在加载评论...