算法训练 Bit Compressor

试题 算法训练 Bit Compressor

资源限制
时间限制: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

#include<stdio.h>
#include<string.h>
#pragma warning (disable:4996)
#define maxn 50
int L, l, N;//全局变量
char data[maxn];//往往用来存放字符串
int answer;
void dfs(int i, int length, int num_1) //dfs深度优先搜索算法,bfs广度优先搜索算法
{
    //i是原串第i个字符,length是变换后的串长,num_1是变换后串的1累计个数 (部分串,并非整个原串)
    if (i == l) 
    {		//最后一个位置 
        dfs(i + 1, length + 1, num_1 + data[i] - '0');
        return;		//最后一个位置是0的话data[i]-'0' =0  是1的话data[i]-'0'=1
    }               //由字符型转化为整形
    if (i > l) {	//结束条件 
        if (length == L && num_1 == N)	//字符串的长度和1的个数正好匹配
            answer++;
        return;
    }

    if (length > L || num_1 > N || answer >= 2)	//不符合条件,提前返回 
        return;

    if (data[i] == '0') {	//如果这一位为0,那么不用考虑情况
        dfs(i + 1, length + 1, num_1);
        return;
    }

    // 以下为 data[i]=='1' 的情况
    if (data[i - 1] == '1')
        //即...11... 在处理上一个1或者更久之前已经考虑过了,注意看下面6行的代码 
        return;

    //以下是data[i-1]=='0'的情况
    if (data[i + 1] == '0')
        //即 ...010... 的情况,这种情况考虑的是1不压缩的情况
        dfs(i + 1, length + 1, num_1 + 1);
    if (data[i + 1] == '1' && data[i + 2] != '1')
        //即 ...0110... 这种考虑的是不压缩的情况
        dfs(i + 2, length + 2, num_1 + 2);
    //注意,以上两种情况1均有可能代表压缩的情况,比如...0110.. 原串为...011110...压缩了3个1
    //下面的代码对每一个1均考虑其为压缩  
    long long temp = 0;
    for (int j = i; j <= l; j++) {
        temp *= 2;
        temp += data[j] - '0';
        //上面两行代码实现二进制转十进制,就是解压缩后1的个数
        if (temp + num_1 > N || temp + length > L)
            //如果解压缩的编码长度或者1的个数比原来的大,不可行,返回
            break;
        if (temp > j - i + 1 && data[j + 1] != '1')
            //压缩的串1比原来多,并且下一个位置为0或者末尾,就是可行解,继续深搜
            dfs(j + 1, temp + length, num_1 + temp);
    }
}
int main()
{
    scanf("%d", &L);		//原串长
    scanf("%d", &N);		//原来1的个数 
    scanf("%s", data + 1);//此种写法并不会影响字符串的长度
    l = strlen(data + 1);		//新串长 
    answer = 0;
    dfs(1, 0, 0);
    if (answer == 0)
        printf("NO");//原串不存在
    else if (answer == 1)
        printf("YES");//原串存在但不唯一
    else
        printf("NOT UNIQUE");//原串存在且唯一
    return 0;
}
#include <stdio.h>
#include <string.h>
char bin[45];
int L, N, binlen;
int ans, one, lens;
void dfs(int i)
{
    int j, spans, spone;
    if (lens > L || one > N || ans > 1)
        return;
    if (i == binlen)
    {
        if (lens + one == L + N)
            ++ans;
        return;
    }
    if (bin[i] == '0')
    {
        ++lens;
        dfs(i + 1);
        --lens;
        return;
    }
    for (j = i, spans = 0, spone = 0; j != binlen; ++j)
    {
        spans = spans * 2 + (bin[j] - '0');
        spone += bin[j] - '0';
        if (spans > 128000)
            return;
        if (j + 1 != binlen && bin[j + 1] - '0')
            continue;
        if (spans > 2)
        {
            lens += spans, one += spans;
            dfs(j + 1);
            lens -= spans, one -= spans;
        }
        if (j - i <= 1 && spans != 2)
        {
            lens += spone, one += spone;
            dfs(j + 1);
            lens -= spone, one -= spone;
        }
    }
}
int main(void)
{
    scanf("%d%d%s", &L, &N, bin);
    binlen = strlen(bin);
    dfs(0);
    if (ans > 1)
        puts("NOT UNIQUE");
    else if (ans < 1)
        puts("NO");
    else
        puts("YES");
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值