更新历史
洛谷传送门
CF 传送门
题意
构造 n 个 01 字符串,使得它们的长度依次为 len1,len2,…lenn,并且不存在一个字符串是另一个字符串的前缀。
输出这 n 个字符串,或指出无解。
思路
学过哈夫曼编码的同学应该知道,这题等价于:构造一颗二叉树,使得它有 n 个叶子,并且每个叶子的深度(从 0 开始)为 len1 到 lenn。
如图(样例1),若将除了叶节点的每个节点,左儿子标上 0,右儿子标上 1,则从根到每个叶结点的路径上经过的数连起来,就是这个叶节点对应的字符串。
那问题就变得简单了很多,只要在满二叉树上进行dfs遍历,碰到深度为 len1 到 lenn 中某一个的节点,就把这个节点当成叶结点,并记录答案,不继续向下递归。
若递归结束还有一些 len 没有答案,就输出 NO。
我用的是栈存每个 len 对应的答案位置,所以代码比较简短,也顺利拿下洛谷最优解。
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| #include <bits/stdc++.h> using namespace std; int n,sum; stack<int>p[1005]; string ans[1005]; void dfs(string s){ int len=s.length(); if(!p[len].empty()){ ans[p[len].top()]=s; p[len].pop(),sum++; if(sum==n){ printf("YES\n"); for(int i=1;i<=n;i++) cout<<ans[i]<<"\n"; exit(0); } return; } dfs(s+"0");dfs(s+"1"); } int main(){ scanf("%d",&n); for(int i=1,len;i<=n;i++){ scanf("%d",&len); p[len].push(i); } dfs(""); printf("NO\n"); return 0; }
|