UVa 129

题目描述:

image-20201220184552977

image-20201220184621482

代码:

int dfs(int cur)
{
    if (cnt++ == n)
    {
        for (int i = 0; i < cur; i++)
        {
            printf("%c", 'A' + S[i]); // 输出方案
        }
        printf("\n");
        return 0;
    }
    for (int i = 0; i < L; i++)
    {
        S[cur] = i;
        int ok = 1;
        for (int j = 1; j * 2 <= cur + 1; j++)
        { // 尝试长度为 j * 2 的后缀
            int equal = 1;
            for (int k = 0; k < j; k++)
            {
                if (S[cur - k] != S[cur - k - j])
                {
                    equal = 0;
                    break;
                }
            }
            if (equal)
            {
                ok = 0;
                break;
            }
        }
        if (ok)
        {
            if (!dfs(cur + 1))
            { // 递归搜索。如果已经找到解,则直接退出
                return 0;
            }
        }
    }
    return 1;
}

关于

for (int j = 1; j * 2 <= cur + 1; j++)
{ // 尝试长度为 j * 2 的后缀
    int equal = 1;
    for (int k = 0; k < j; k++)
    {
        if (S[cur - k] != S[cur - k - j])
        {
            equal = 0;
            break;
        }
    }
    if (equal)
    {
        ok = 0;
        break;
    }
}

的说明:

当递归到了 cur 时,从后往前尝试是否有相邻的重复的字串。j 从 1 开始,然后到 \(\displaystyle \frac{cur + 1}{2}\) 结束,先从右往左探测长度为 1 的相邻字串是否是重复的,然后探测长度为 2 的...

Q:为什么只需要从当前项 cur 开始探测呢,需要以 cur 的前一项为起点进行探测吗?

A:因为去掉 cur 的字串是困难的串,所以我们只需要以 cur 为起点进行探测就好了。这里,我们省去了很多无用功,因为我们只需要判断当前串的后缀,而非所有的字串。

完整测试代码:

#include <iostream>

int cnt = 0; // 计数器
int n = 0;
int L = 0;
int S[80] = {0};

int dfs(int cur)
{
    if (cnt++ == n)
    {
        for (int i = 0; i < cur; i++)
        {
            printf("%c", 'A' + S[i]); // 输出方案
        }
        printf("\n");
        return 0;
    }
    for (int i = 0; i < L; i++)
    {
        S[cur] = i;
        int ok = 1;
        for (int j = 1; j * 2 <= cur + 1; j++)
        { // 尝试长度为 j * 2 的后缀
            int equal = 1;
            for (int k = 0; k < j; k++)
            {
                if (S[cur - k] != S[cur - k - j])
                {
                    equal = 0;
                    break;
                }
            }
            if (equal)
            {
                ok = 0;
                break;
            }
        }
        if (ok)
        {
            if (!dfs(cur + 1))
            { // 递归搜索。如果已经找到解,则直接退出
                return 0;
            }
        }
    }
    return 1;
}


int main()
{
    n = 30;
    L = 3;
    dfs(0);
    return 0;
}

测试 n = 7,L = 3 和 n = 30,L = 3 的输出分别为:

ABACABA

ABACABCACBABCABACABCACBACABA

posted @ 2020-12-20 18:50  模糊计算士  阅读(75)  评论(0编辑  收藏  举报