Codevs 1018 单词接龙 DFS --2000年NOIP全国联赛普及组NOIP全国联赛提高组

Codevs 1018 单词接龙

DFS 深搜。

加入第一个单词时,我们判断它能不能是第一个单词,这只需要比较这个单词的第一个字符,与数据给定的字符是否一样就行了。

加入后面的字符时,我们需要检查这个单词是否可以 与前面的单词对接起来, 这个检查由check 函数实现。

check函数:枚举 k 从 1 到 min(2个单词的长度), 作为暴力枚举2个单词有 k 个重叠字符。 所以说, 当枚举到 有 k 个重叠字符时,我们枚举 要拼接的2个单词中的前面的单词 的后 k 位 和 后面的单词 的前 k 位,一旦有 k 可以 使 这 2 个单词的 k 位的每一位都相等, 我们就返回 k, 因为显然重叠的越少, 最后达到的长度越长。
至于 枚举 k 到min (2个单词的长度),是因为 重叠部分的长度肯定不能 >= 其中任意一个单词的长度, 否则就是包含或者相等了。

代码:

#include 
#include 
#include 
#include 
using namespace std;

const int MAXN = 100 + 10;
int n, ans = 0;
int use[MAXN];
struct WORD{
    char a[MAXN];
}s[MAXN];

int check(int l, int n)
{
    int l_l = strlen(s[l].a), l_n = strlen(s[n].a);
    for(int k = 1; k < min(l_n, l_n); k ++)
    {
        bool h = 1;
        for(int i = l_l-k, j = 0; i < l_l, j < k; i ++, j ++)
        {
            if(s[l].a[i] != s[n].a[j])
            {
                h = 0;
                break;
            }
        }
        if(h)
            return k;
    }
    return 0;
}

void dfs(int last, int len)
{
    if(!last)
    {
        for(int i = 1; i <= n; i ++)
        {
            if(s[i].a[0] == s[0].a[0])
            {
                if(use[i] < 2)
                {
                    use[i] ++;
                    dfs(i, strlen(s[i].a));
                    use[i] --;
                }
            }
        }
    }
    else{
        ans = max(ans, len);
        for(int i = 1; i <= n; i ++)
        {
            int x = check(last, i);
            if(x && use[i] < 2)
            {
                use[i] ++;
                dfs(i, len+strlen(s[i].a)-x);
                use[i] --;
            }
        }
    }
}

int main()
{
    scanf("%d", &n);
    for(int i = 1; i <= n; i ++)
        scanf("%s", s[i].a);
    scanf("%s", s[0].a);
    dfs(0,1);
    cout << ans << endl;
    return 0;
}

你可能感兴趣的:(搜索,真·NOIP试题,dfs)