DFS+邻接表+KMP,两个测试点错误,求大佬相助
查看原帖
DFS+邻接表+KMP,两个测试点错误,求大佬相助
695872
Rinkan楼主2024/9/12 22:04
#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
#include<vector>

using namespace std;
const int N = 25, maxm = 1e5 + 10;
int n;
string s[N];
string str, ptr, ans;
int h[N * N], e[N * N], ne[2 * N * N], idx;
int st[N * N];
vector<int>q;
int maxi = 0;
int g[N][N];
void DFS(int num, int len);
void add(int a, int b);
int kmp(string s1, int len1, string s2, int len2);
void cal_next(string s1, int* next, int len);
void test();
int MaxLenth(string s);
int MaxLenth(string s) // 有时候要允许自环的存在,因此这个函数是为了记录相同的字符串前后缀的最小值
{
    int i = 0, j = s.size() - 1;
    string s1, s2;
    s1 = s2 = "";
    while (i < s.size() - 1)
    {
        if (s1 == s2)
        {
            if (s1.empty())
            {
                s1 += s[i], s2 += s[j];
                i++, j--;
            }
            else
            {
                //cout << s1 << " " << s2 << endl;
                return i;
            }
        }
        else
        {
            s1 += s[i];
            string temp = "";
            temp += s[j];
            temp += s2;
            s2 = temp;
            i++, j--;
        }
    }
    return 0;
}
void add(int a, int b) // 邻接矩阵法建立有向边
{
    e[idx] = b;
    ne[idx] = h[a];
    h[a] = idx;
    idx++;
}
void DFS(int num, int len)
{
    //if (st[num] > 2)
    //{
    //    //cout << num << " ";
    //    maxi = max(maxi, len);
    //    return;
    //}
    if (g[num][num] > 0) // 如果有自环首先迭代自环
    {
        st[num]++;
        if(st[num] <= 2) DFS(num, len + s[num].size() - g[num][num]); // 如果当前字符串已经被使用两次将不会再迭代
        st[num]--;
    }
    for (int i = h[num]; i != -1; i = ne[i]) // 从邻接表中选择元素
    {
        st[e[i]]++;
        if(st[e[i]] <= 2) DFS(e[i], len - g[num][e[i]] + s[e[i]].size()); // 更新长度以及进入的单词编号
        st[e[i]]--;
    }
    maxi = max(maxi, len);
}
void cal_next(string s1, int* next, int len)
{
    next[0] = next[1] = 0; // next[0]和next[1]都初始化为0  
    for (int i = 1; i < len; ++i) // 从第二个字符开始遍历模式串  
    {
        int j = next[i]; // 从当前位置的前一个next值开始匹配  
        while (j && s1[i] != s1[j]) // 如果不匹配且j不为0,则回退到next[j]  
            j = next[j];
        next[i + 1] = (s1[j] == s1[i]) ? j + 1 : 0; // 如果匹配,则next[i+1]为j+1,否则为0  
    }
}
int kmp(string s1, int len1, string s2, int len2) // 计算不同字符串之间的前后缀值
{
    int next[maxm];
    cal_next(s1, next, len1);

    int j = 0;
    for (int i = 0; i < len2; i++)
    {
        while (j && s1[j] != s2[i]) j = next[j];
        if (s1[j] == s2[i]) ++j;
    }
    return j;
}
void test()
{
    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j <= n; j++)
            cout << g[i][j] << " ";
        cout << endl;
    }
}
int main()
{
    memset(h, -1, sizeof h);
    cin >> n;
    for (int i = 1; i <= n; i++) cin >> s[i];
    char c;
    cin >> c;
    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j <= n; j++)
        {
            int plen = s[i].size(), slen = s[j].size();
            if (i != j)
            {
                g[j][i] = kmp(s[i], plen, s[j], slen); // 判断两个字符串是否首尾相连,并把长度计算出来
                g[i][j] = kmp(s[j], slen, s[i], plen);
                if (g[i][j]) add(i, j); // 建立一条有向边
                if (g[j][i]) add(j, i);
            }
            else
            {
                g[i][j] = MaxLenth(s[i]);
            }
        }
    }
    for (int i = 1; i <= n; i++)
        if (s[i][0] == c) q.push_back(i); // 判断输入的字符串第一个字母是否等于指定字母,若相等则可以作为第一个单词

    for (auto p : q)
    {
        st[p]++;
        if(st[p] <= 2) DFS(p, s[p].size());
        st[p]--;
    }
    cout << maxi << endl;
    //test();
    return 0;
}
2024/9/12 22:04
加载中...