Problema de conmutación (método de eliminación gaussiano)

Límite de tiempo total: 1000ms
Límite de memoria: 65536kB

Descripción
de N interruptores idénticos, cada interruptor tiene un contacto determinado, cada vez que abre o cierra un interruptor cuando el otro interruptor asociado con este interruptor cambiará en consecuencia, estas fases, es decir, si el estado del interruptor asociado estaba originalmente encendido, cambiaría a apagado, y si estaba apagado, cambiaría a encendido. Su objetivo es hacer que los últimos N conmutadores alcancen un estado específico después de varias operaciones de conmutador. Para cualquier interruptor, solo se puede realizar una operación de interruptor como máximo. Su tarea es calcular cuántas formas de alcanzar un estado específico. (No cuenta la secuencia de operaciones del interruptor)

Entrada
Hay un número K en la primera línea de entrada, lo que indica que hay K grupos de datos de prueba a continuación.
El formato de cada grupo de datos de prueba es el siguiente: la
primera línea tiene un número N (0 <N <29) y la
segunda línea tiene N 0 o 1 números, lo que indica los N estados del interruptor al principio.
El número de N 0 o 1 en la tercera fila indica el estado de los N conmutadores después de que se completa la operación.
Los siguientes dos números IJ en cada línea indican que si se opera el interruptor I, el estado del interruptor J también cambiará. Cada grupo de datos termina con 0 0.

Salida
Si hay un método factible, envíe el número total, de lo contrario, envíe "¡Oh, es imposible ~!" Sin comillas

Entrada de muestra
2
3
0 0 0
1 1 1
1 2
1 3
2 1
2 3
3 1
3 2
0 0
3
0 0 0
1 0 1
1 2
2 1
0 0

La salida de muestra es
4
¡¡Oh, es imposible ~ !!

Solicitud
Descripción del primer grupo de datos:
Hay cuatro métodos en total:
Interruptor de
operación 1 Interruptor de operación 2
Interruptor de
operación 3 Interruptor de operación 1, 2, 3 (no registrar la orden)

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;

const int MAXN = 35;
bool a[MAXN][MAXN];

inline int read() {
    
    
    int x; scanf("%d", &x); return x;
}

int gauss(int n)
{
    
    
    int rank = 0;
    for (int d = 0; d < n; ++d) {
    
     /* d for diagonal */
        int i;
        /* try to find first line whose d'th element = 1 */
        for (i = d; i < n; ++i)
            if (a[i][d] == 1)
                break;

        /* not found */
        if (i == n)
            continue;
        
        /* found */

        /* Step 1: make the d'th element of rank'th line to be 1, by swapping i'th line and rank'th line, including the rightmost column */
        for (int j = 0; j <= n; ++j) 
            swap(a[rank][j], a[i][j]);
        /* Step 2: eliminating the following line if the d'th element = 1, including the rightmost column */
        for (i = rank+1; i < n; ++i) 
            if (a[i][d])
                for (int j = 0; j <= n; ++j) 
                    a[i][j] ^= a[rank][j];

        ++rank;
    }

    /* up to now, the rank+'th line should be all 0 */
    /* if the rightmost column is 1, bad equation, return -1 */
    for (int i = rank; i < n; ++i)
        if (a[i][n])
            return -1;

    /* otherwise, return the rank */
    return rank;
}

int main()
{
    
    
    int K = read();
    for (int k = 0; k < K; ++k) {
    
    
        memset(a, 0, sizeof(a));
        int N = read();
        for (int i = 0; i < N; ++i) 
            a[i][N] ^= read();
        for (int i = 0; i < N; ++i) 
            a[i][N] ^= read();
        for (int x = 0; x < N; ++x)
            a[x][x] = 1;
        for (;;) {
    
    
            int x = read()-1, y = read()-1;
            if (x == -1)
                break;
            a[y][x] = 1;
        }
        int rank = gauss(N);
        if (rank == -1)
            printf("Oh,it's impossible~!!\n");
        else 
            printf("%d\n", 1<<(N-rank));
    }
    system("pause");
    return 0;
}
análisis
  1. En cuanto al método de eliminación gaussiano, los comentarios del código han sido muy detallados. La función gauss es en realidad una función de resolución general. Si no hay solución, devuelve -1, y si hay solución, devuelve el rango de la matriz.
  2. Array a, las filas representan interruptores y las columnas representan soluciones (cada interruptor "lidera" una solución, por lo que el número de filas y columnas es igual)
  3. Por qué se puede eliminar puede entenderse como la definición de un problema de equivalencia, y la solución del problema de equivalencia corresponde a la solución del problema original uno a uno. La eliminación gaussiana hace esto, y la operación OR exclusiva es reversible, por lo que no hay problema.
  4. No solo la eliminación de filas es equivalente, sino que la eliminación de columnas también es equivalente. En el código, calculamos el rango por eliminación de filas, y luego podemos compensarlo y realizar la eliminación de columnas, y finalmente solo queda 1 en la diagonal.
  5. Se deben tomar las filas con 1, las filas sin 1 se pueden tomar o no, por lo que el número final de planes es 2 n - rango 2 ^ {n-rango}2n - r a n k

Esta pregunta nos permite revisar el exquisito método de eliminación gaussiano desde la perspectiva algebraica.

Supongo que te gusta

Origin blog.csdn.net/w112348/article/details/110941960
Recomendado
Clasificación