洛谷題單指南-搜尋-P1019 [NOIP2000 提高組] 單詞接龍

江城伍月發表於2024-03-07

原題連結:https://www.luogu.com.cn/problem/P1019

題意解讀:要計算接龍能得到的最長字串,可以透過DFS暴搜所有可能的接龍方案

解題思路:

DFS的關鍵在於兩個判斷:

1、下一個單詞是否可以和上一個單詞接龍,最短公共長度是多少(只需要看兩個單詞的最短公共長度,這樣能保證接龍更長)

2、單詞是否已接龍兩次

判斷2透過int flag[N]即可解決,下面重點討論判斷1如何處理

設int conn[i][j]表示在第i個單詞後接第j個單詞時,最少的公共長度,如果為0說明不能接

透過雙重迴圈列舉所有單詞,可以得到兩兩之間的最少公共長度

具體說來:

只需要針對兩個單詞s1、s2,從1開始列舉公共長度k(不能超過任意字串的長度,因為不能存在包含關係)

判斷s1的後k位是否和s2的前k位相同,找到則儲存最小的k,詳細過程請參考程式碼。

100分程式碼:

#include <bits/stdc++.h>
using namespace std;

const int N = 25;

int conn[N][N]; //conn[i][j]表示第i個單詞後接第j個單詞時,最少的公共長度,如果為0說明不能接
string s[N]; //所有單詞
int flag[N]; //每個單詞被用了多少次
int n;
char first;
int ans;

//str:接龍 idx:上一個接上的單詞
void dfs(string str, int idx)
{
    ans = max(ans, (int)str.length());
    
    for(int i = 1; i <= n; i++)
    {
        if(conn[idx][i] > 0 && flag[i] < 2) //如果存在可接龍的單詞
        {
            string longstr = str; //接龍後的字串
            for(int j = conn[idx][i]; j < s[i].length(); j++)
            {
                longstr += s[i][j]; //接龍操作
            }
            flag[i]++;
            dfs(longstr, i); //繼續找下一個可接龍的單詞
            flag[i]--;
        }
    }
}

int main()
{
    cin >> n;
    for(int i = 1; i <= n; i++) cin >> s[i];
    cin >> first;

    //計算每兩個單詞相接的最短公共長度,由於不能存在包含關係,公共長度要小於長度較小的字串
    for(int i = 1; i <= n; i++)
    {
        for(int j = 1; j <= n; j++)
        {
            for(int k = 1; k < min(s[i].length(), s[j].length()); k++) //列舉公共長度可能的值
            {
               
                bool isk = true; //公共長度是否是k
                string s1 = s[i]; int start1 = s1.length() - k;
                string s2 = s[j]; int start2 = 0;
                
                for(int l = 1; l <= k; l++)
                {
                    if(s1[start1] != s2[start2])
                    {
                        isk = false;
                        break;
                    }
                    start1++; start2++;
                }

                if(isk)
                {
                    conn[i][j] = k;
                    break; //找到最短的公共長度,就應該結束,這樣才能保證接上的龍最長
                } 
            }
        }
    }

    for(int i = 1; i <= n; i++)
    {
        if(s[i][0] == first) 
        {
            memset(flag, 0, sizeof(flag)); //從每一個可能的單詞開始dfs,都需要重置flag
            flag[i]++;
            dfs(s[i], i);
        }
    }

    cout << ans;

    return 0;
}

相關文章