Guía avanzada para la competencia de algoritmos --- Rejilla de ordeño 0x18 (KMP)

Tema

Inserte la descripción de la imagen aquí

responder

  1. Para buscar una matriz de cobertura mínima, podemos separarla horizontal y verticalmente. Primero, observe la dirección horizontal. Para cada fila, enumeramos directamente la longitud de la sección del bucle para determinar si cada fila se encuentra o no, y finalmente obtenemos un mínimo horizontal longitud de la sección de bucle (ancho)
  1. Para la dirección vertical, podemos considerar cada línea como una letra y luego realizar KMP vertical para encontrar la matriz ne, luego n-ne [n] es la longitud mínima de la sección del bucle (altura)
  1. Explicación 1: ¿Por qué encontrar el nodo de bucle horizontal más pequeño para obtener el área final más pequeña, en lugar de hacer que el ancho sea más grande y la altura más pequeña, porque si aumenta el ancho, solo tendrá caracteres diferentes cuando busque el KMP vertical? Más cadenas, el El valor de la matriz ne requerida se vuelve más pequeño y la altura aumenta
  1. Explicación 2: Al buscar la sección de bucle horizontal, ¿puede encontrar la sección de bucle más pequeña de cada línea y luego tomar el mínimo común múltiplo, por supuesto que no, porque para secciones de bucle de cadena como abcabcabc, puede ser 3 (abc), 6 (abcabc), 9 es un múltiplo de 3, pero para aaabaa, la sección de bucle puede ser 4 (aaab), 5 (aaaba), por lo que no hay una relación múltiple, por lo que no puede encontrar el mínimo común múltiplo, por supuesto, no puede tomar un número máximo de cada línea, solo puede enumerar la longitud de la sección del bucle de 1 a m, para ver si cada línea cumple
  1. Dado m <= 75, n <10000 en la pregunta, entonces podemos aceptar O (n 2 * m)

Código

#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;
}

Supongo que te gusta

Origin blog.csdn.net/qq_44791484/article/details/114107904
Recomendado
Clasificación