蓝桥杯练习 | Bit Compressor

问题描述

数据压缩的目的是为了减少存储和交换数据时出现的冗余。这增加了有效数据的比重并提高了传输速率。有一种压缩二进制串的方法是这样的:
将连续的n个1替换为n的二进制表示(注:替换发生当且仅当这种替换减少了二进制串的总长度)
(译者注:连续的n个1的左右必须是0或者是串的开头、结尾)
比如:11111111001001111111111111110011会被压缩成10000010011110011。原串长为32,被压缩后串长为17.
这种方法的弊端在于,有时候解压缩算法会得到不止一个可能的原串,使得我们无法确定原串究竟是什么。请你写一个程序来判定我们能否利用压缩后的信息来确定原串。给出原串长L,原串中1的个数N,以及压缩后的串。
L<=16 Kbytes,压缩后的串长度<=40 bits。

输入格式

第一行两个整数L,N,含义同问题描述
第二行一个二进制串,表示压缩后的串

输出格式

输出 "YES" 或 "NO" 或 "NOT UNIQUE"(不包含引号)
分别表示:
YES:原串唯一
NO:原串不存在
NOT UNIQUE:原串存在但不唯一

样例输入

样例1:

32 26
10000010011110011

样例2:

9 7
1010101

样例3:

14 14
111111

样例输出

样例1:YES
样例2:NOT UNIQUE
样例3:NO

—————————————————————————————————

思路

数据范围较小,可以直接 BFS 暴力构造答案

node 结构体里的 p、l、n 分别表示当前压缩串处理了 p 位,原串构造了前 l 位,其中有 n 个 1

如果当前节点状态超过越界,则舍弃,若还能切分构造则继续加入队列,正好符合答案则 ans++

注意原串中连续的 1 必须被 0 分隔,所以 node 中的 v 标识已还原的最末字符串是否是 1

接下来遇到 0 时就把 v 清零。最后根据 ans 的值输出相应的结果

代码如下

#include <bits/stdc++.h>
#define MAXN 233 
using namespace std;
struct node { int p,l,n,v; }; 
queue<node> Q;
int l,n,len,ans; char v[MAXN];
inline int fun(int s,int t) { // 二进制转换成十进制
	int ret=1;
	for (int i=s+1;i<=t;i++) {
		if (v[i]=='1') ret=(ret<<1)+1;
		else ret<<=1;
	}
	return ret;
}
int main() {
	scanf("%d%d%s",&l,&n,v+1),len=(int)strlen(v+1);
	Q.push((node){0,0,0,0});
	while (!Q.empty()) {
		node now=Q.front(); Q.pop();
		while (v[now.p+1]=='0' && now.p<len) now.p++,now.l++,now.v=0; // 把接下来的 0 都略过,累计未压缩 0 的长度
		if (now.p==len && now.l==l && now.n==n) { ans++; continue; } // 正好符合题意
		//此时 v[now.p+1] = '1'
                for (int i=now.p+1;!now.v && i<=len;i++) {
			int t=fun(now.p+1,i); // 视为压缩后的 1 的长度 -> [now.p+1,i]
                        //此时 t 为要加入原串中的 1 的长度
			if (now.l+t<=l && now.n+t<=n) Q.push((node){i,now.l+t,now.n+t,1}); 
		}
	}
	if (ans==1) puts("YES");
	else puts(ans?"NOT UNIQUE":"NO");
	return 0;
} 
posted @ 2020-10-29 21:24  暖暖草果  阅读(150)  评论(0编辑  收藏  举报