Guide avancé de la concurrence des algorithmes --- Grille de traite 0x18 (KMP)

Sujet

Insérez la description de l'image ici

répondre

  1. Pour rechercher une matrice de couverture minimale, nous pouvons la séparer horizontalement et verticalement. Tout d'abord, regardez la direction horizontale. Pour chaque ligne, nous énumérons directement la longueur de la section de boucle pour déterminer si chaque ligne se rencontre ou non, et enfin obtenir un minimum horizontal longueur de section de boucle (largeur)
  1. Pour la direction verticale, nous pouvons considérer chaque ligne comme une lettre, puis effectuer un KMP vertical pour trouver le tableau ne, puis n-ne [n] est la longueur minimale de la section de boucle (hauteur)
  1. Explication 1: Pourquoi trouver le plus petit nœud de boucle horizontale pour obtenir la plus petite zone finale, au lieu de rendre la largeur plus grande et la hauteur plus petite, car si vous augmentez la largeur, vous n'aurez que des caractères différents lorsque vous recherchez les chaînes verticales KMP More, le la valeur du tableau ne requis devient plus petite et la hauteur devient plus grande
  1. Explication 2: Lorsque vous recherchez la section de boucle horizontale, pouvez-vous trouver la plus petite section de boucle de chaque ligne, puis prendre le multiple le moins commun, bien sûr que non, car pour les sections de boucle de chaîne comme abcabcabc, cela peut être 3 (abc), 6 (abcabc), 9 est un multiple de 3, mais pour aaabaa, la section de boucle peut être 4 (aaab), 5 (aaaba), donc il n'y a pas de relation multiple, donc vous ne pouvez pas trouver le plus petit multiple commun, bien sûr, ne peut pas prendre un nombre maximum de chaque ligne, peut seulement énumérer la longueur de la section de boucle de 1 à m, pour voir si chaque ligne rencontre
  1. Étant donné m <= 75, n <10000 dans la question, alors nous pouvons accepter O (n 2 * m)

Code

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>

using namespace std;
const int N = 10010, M = 80;

int n, m;
char str[N][M];
int ne[N];
bool st[M];

int main() {
    
    

    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);

    memset(st, true, sizeof st);

    cin >> n >> m;

    //横向暴力枚举
    for (int i = 1; i <= n; i++) {
    
    
        cin >> str[i];
        for (int j = 1; j <= m; j++) {
    
    
            if (st[j]) {
    
    
                for (int k = j; k < m; k += j) {
    
    
                    for (int u = 0; u < m && u + k < m; u++) {
    
    
                        if (str[i][u] != str[i][u + k]) {
    
    
                            st[j] = false;
                            break;
                        }
                    }
                    if (!st[j]) break;
                }
            }
        }
    }

    int width;
    for (int i = 1; i <= m; i++) {
    
    
        if (st[i]) {
    
    
            width = i;
            break;
        }
    }

    //将每行的循环节转化为字符串
    for (int i = 1; i <= n; i++) str[i][width] = '\0';

    //纵向KMP(将每行看成一个字母)
    for (int i = 2, j = 0; i <= n; i++) {
    
    
        while (j && strcmp(str[i], str[j + 1])) j = ne[j];
        if (!strcmp(str[i], str[j + 1])) j++;
        ne[i] = j;
    }

    int heigth = n - ne[n];

    cout << heigth * width << endl;

    return 0;
}

Je suppose que tu aimes

Origine blog.csdn.net/qq_44791484/article/details/114107904
conseillé
Classement