题目:
资源限制
时间限制:1.0s 内存限制:256.0MB
问题描述
数据压缩的目的是为了减少存储和交换数据时出现的冗余。这增加了有效数据的比重并提高了传输速率。有一种压缩二进制串的方法是这样的:
将连续的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
分析:
- 新、原串易搞混,这里用长串、短串表示。题目即意为:已知短串,长串长L(L<1610248=131072位),长串含1的个数N(N<40位),求长串是否唯一。我设定长串通过“编码”得到短串,短串通过“译码”得到长串。这里的编码方式就是十进制转二进制,反之,译码方式就是二进制转十进制。
- 通过DFS搜索短串,还原成长串。搜索原则是译码成1的个数由少到多。
- 必须以1开头,如果有连续的1,必须在一起译,即译码的结尾不能是1.
- 010只能译码成1,0110既可以译码成11,也可以译码成111,之后都是一一对应
代码:
#include <iostream>
#include <string.h>
using namespace std;
int L,N,l;//L为长串长度,N为长串1的个数,l为短串长度
char a[50];//存储短串(从1开始)
int flag=0;//成功匹配的次数,0代表失败,2及以上代表歧义
void dfs(int num_1, int len, int i)//num_1为目前译码的1的数量,len为目前译码得到的长码长度,i为需要译码的起始位置
{
if(i==l)//当短码最后一位为译码开始的地方
{
dfs(num_1+a[i]-'0',len+1,i+1);
return;
}
if(i>l)//一轮译码结束
{
if(len==L && num_1==N)
{
flag++;
}
return;
}
if(len>L || num_1>N || flag>=2) return;//显然如果发生以上三种情况,可以退出
if(a[i]=='0')//0的话只要继续下一步译码,num_1不变
{
dfs(num_1,len+1,i+1);
return;
}
//下面讨论a[i]==1的情况
if(a[i-1]=='1') return;//和0110、010匹配,因为之前已经算过了
long long temp=0;//计算i~j这一块二进制几个1,虽然题目中最多16*1024*8=131072位,在int范围内,但在译码的时候可能超过
if(a[i+1]=='0')//类似010
{
dfs(num_1+1,len+1,i+1);
//不写return是因为如果单独译码不行,还要继续连着后面译码,例如10100可以译成101111和1111100,因此还需要参加for循环
}
if(a[i+1]=='1' && a[i+2]!='1')//类似0110,这里不用=='0'是因为可能溢出
{
dfs(num_1+2,len+2,i+2);
}
//三或三个以上的1同时出现,或者0110解释成11不能满足条件
for(int j=i;j<=l;j++)
{
temp*=2;//左移一位
temp+=a[j]-'0';//译码完成
if(temp+num_1>N || temp+len>L) break;//失败
if(temp>j-i+1 && a[j+1]!='1')//省略了010的重复搜索
dfs(num_1+temp,len+temp,j+1);//i~j的一次译码,a[j+1]为0或溢出
}
}
int main()
{
cin>>L>>N;
cin>>(a+1);
l=strlen(a+1);
dfs(0,0,1);
if(flag==1) cout<<"YES"<<endl;
if(!flag) cout<<"NO"<<endl;
if(flag>=2) cout<<"NOT UNIQUE"<<endl;
return 0;
}
总结:
有关DFS搜索:本题的搜索较复杂,需要讨论的部分比较多,建议先挑明显的先写掉,比如结束条件。之后的关于010、0110的特别搜索,要反复斟酌。
改写自链接:https://blog.csdn.net/Yi_Qing_Z/article/details/88084875