蓝桥杯:算法训练 Bit Compressor

被训练系统的标签误导,不能用DP求解,这不是一个最值问题,状态复杂不易记录采用DFS搜索求解

简要分析:

阅读题意可以发现,在原串中:

  1. 连续一长串1,且长度大于2时必然会被加密。(如:111 -> 11、1111 -> 100、11111 ->101 等等)
  2. 单个1、单个0、连续两个1的情况不会被加密。

因而可以推断出,在解密串中:

  1. 任何以0开头的子串,都是未被加密过的。
  2. 以1为开头的子串中,长度小于等于2,且不是10的子串都可能是未被加密过的。(如:1、11)
  3. 以1为开头的子串中,将串认为是二进制数,大于11(十进制的3)的,都可能是被加密过的。(如:11 -> 111、100 -> 1111、101 -> 11111 等等)

根据以上分析,编写 dfs 函数,当搜索时原串的长度和包含1的数量超出限制,或者搜索到两个结果时,立即停止搜索。

另:题目注明了原串长度不超过16 Kbytes,所以解密串时不可能出现大于 128000 的。限制最长解密的最大值为128000。

ANSI C:

#include 
#include 
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;
}

 

END

你可能感兴趣的:(蓝桥杯)