Pulizie d’autunno (trendytrash) 58/100

Sto provando a risolvere trendytrash, ma il codice va fuori tempo in 3 o 4 testcases dell’ultimo subtask. Ho provato ad aggiungere quante più ottimizzazioni mi venissero in mente, ma il risultato rimane sempre lo stesso. Voi sapreste dirmi qualche possibile miglioramento?

#include <bits/stdc++.h>

using namespace std;

// total all'inizio è il numero di sacchetti, poi diventa il risultato
int tot, tolto_temp, tolto;

int check_colonna(int N, int M, int r, int c, vector<string> &S, int righe[]) {
    int i, counter = 0;

    for(i=r; i<N-1; i++) {
        // controlla che l'elemetno non sia segnato nel vettore, se si saltalo
        if(righe[i] == 1) {
           continue;
        }

        // controlla la (in)validità della posizione in cui ci troviamo
        if(S[i][c] != S[r][c]) return 0;

        // è l'elemento che ho tolto nel loop precedente, non serve controllare 
        if(tolto != -1 && tolto != 2 && tolto == S[i][c]-48) return 0;

        counter++;
    }

    // siamo alla fine della linea
    // controllo che l'ultimo sacchetto non sia escluso
    if(righe[i] != 1) counter++;

    // controlla che sia valido l'elemento in cui ti trovi
    if(righe[i] != 1 && S[i][c] != S[r][c]) return 0;
    
    // update del totale
    tot -= counter;

    // ottimizzazione
    // in questo loop non ho ancora tolto nessun sacchetto
    if(tolto_temp == -1) tolto_temp = S[r][c] - 48;

    // ho tolto sia 1 che 0 (entrambi i sacchetti)
    else if (tolto_temp != S[r][c]) tolto_temp = 2;

    return 1;
}

int check_riga(int N, int M, int r, int c, vector<string> &S, int colonne[]) {
    int i, counter = 0;

    for(i=c; i<M-1; i++) {
        // controlla che l'elemetno non sia segnato nella vettore, se si saltalo
        if(colonne[i] == 1) {
           continue;
        }

        // controlla la (in)validità della posizione in cui ci troviamo
        if(S[r][i] != S[r][c]) return 0;

        // è l'elemento che ho tolto nel loop precedente, non serve controllare 
        if(tolto != -1 && tolto != 2 && tolto == S[r][i]-48) return 0;

        counter++;
    }

    // siamo alla fine della linea
    // controllo che l'ultimo sacchetto non sia escluso
    if(colonne[i] != 1) counter++;

    // controlla che sia valido l'elemento in cui ti trovi
    if(colonne[i] != 1 && S[r][i] != S[r][c]) return 0;
    
    // update del totale
    tot -= counter;

    // ottimizzazione
    // in questo loop non ho ancora tolto nessun sacchetto
    if(tolto_temp == -1) tolto_temp = S[r][c] - 48;
    // ho tolto sia 1 che 0 (entrambi i sacchetti)
    else if (tolto_temp != S[r][c]) tolto_temp = 2;

    return 1;
}

int pulisci(int N, int M, vector<string> S) {
    tot = N*M;
    int righe[N] = {}, colonne[M] = {};
    int c_r = 1, c_c = 1, ri = 0, ci = 0, temp_c, temp_r;
    tolto = -1, tolto_temp = -1;

    while(c_r == 1 || c_c == 1) {
        // copio le variabili, mi servono per risparmiare tempo. Se ho tolto solo righe controllo solo le colonne e viceversa
        temp_c = c_c;
        temp_r = c_r;

        // reset variabili di controllo
        c_r = 0, c_c = 0;

        // variabile di controllo per trovare la prima riga / colonna agibile
        int controllo = 0;

        // ho tolto almeno una colonna nel loop precedente, controllo le righe
        if(temp_c == 1) {
            for(int i=ri; i<N; i++) {
                // conotrollo che quetsa riga non sia già eliminata
                if(righe[i] == 1) continue;

                // controllo se = 1 ho tolto la riga, faccio update
                if(check_riga(N, M, i, ci, S, colonne) == 1) {
                    righe[i] = 1;

                    // questa variabile è = 0 all'inizio del loop e cambia solo
                    // se sposto almeno un sacchetto
                    c_r = 1;
                }
                // prendo la prima riga agibile, da utilizzare nel prossimo loop
                else if(controllo == 0) {
                    ri = i;
                    controllo = 1;
                }
            }
        }
        
        // variabile di controllo per trovare la prima riga / colonna agibile
        controllo = 0;
        // ho tolto almeno una riga nel loop precedente, controllo le colonne
        if(temp_r == 1) {
            for(int h=ci; h<M; h++) {
                // conotrollo che quetsa colonna non sia già eliminata
                if(colonne[h] == 1) continue;

                // controllo se = 1 ho tolto la colonna, faccio update
                if(check_colonna(N, M, ri, h, S, righe) == 1) {
                    colonne[h] = 1;

                    // copio in questa variabile, che è = 0 all'inizio del loop e cambia solo
                    // se sposto almeno un sacchetto
                    c_c = 1;
                }
                else if(controllo == 0) {
                    ci = h;
                    controllo = 1;
                }
            }
        }

        // salvo la variabile per il loop successivo
        tolto = tolto_temp;
    }   
    
    return tot;
}

Non ho guardato bene il tuo codice e non so se può essere di aiuto ma a che cosa è uguale il prodotto delle righe rimaste per le colonne rimaste?
Consiglio di precalcolare i contatori degli uni in riga e in colonna ed aggiornarli di conseguenza dopo l’eliminazione di una riga o di una colonna.

Grazie per il consiglio. Ho cambiato il codice rimuovendo le variabili counter e tot. Invece, ho aggiunto due variabili che tengono conto del numero di righe e colonne rimaste e vengono aggiornate ogni volta che ne rimuovo una.

Effettivamente il codice è un po’ più veloce, ma va ancora fuori tempo negli ultimi due testcases dell’ultimo subtask.

UPDATE: Ho trovato un altro errore, stavo controllando delle condizioni inutili quando, nelle funzioni check_colonna e check_riga, guardo se la variabile tolto (che rappresenta l’elemento tolto nel loop precedente) è uguale all’elemento di questa riga / colonna. Ho corretto ora il codice qui sotto, ma fa ancora 58/100.

#include <bits/stdc++.h>

using namespace std;

int n_righe, n_colonne, tolto_temp, tolto;

int check_colonna(int N, int M, int r, int c, vector<string> &S, int righe[]) {
    int i;

    for(i=r; i<N-1; i++) {
        // controlla che l'elemetno non sia segnato nel vettore, se si saltalo
        if(righe[i] == 1) {
           continue;
        }

        // controlla la (in)validità della posizione in cui ci troviamo
        if(S[i][c] != S[r][c]) return 0;

        // è l'elemento che ho tolto nel loop precedente, non serve controllare 
        if(tolto == S[i][c]-48) return 0;
    }

    // siamo alla fine della linea

    // controlla che sia valido l'elemento in cui ti trovi
    if(righe[i] != 1 && S[i][c] != S[r][c]) return 0;

    // ottimizzazione
    // in questo loop non ho ancora tolto nessun sacchetto
    if(tolto_temp == -1) tolto_temp = S[r][c] - 48;

    // ho tolto sia 1 che 0 (entrambi i sacchetti)
    else if (tolto_temp != S[r][c]) tolto_temp = 2;

    return 1;
}

int check_riga(int N, int M, int r, int c, vector<string> &S, int colonne[]) {
    int i;

    for(i=c; i<M-1; i++) {
        // controlla che l'elemetno non sia segnato nella vettore, se si saltalo
        if(colonne[i] == 1) {
           continue;
        }

        // controlla la (in)validità della posizione in cui ci troviamo
        if(S[r][i] != S[r][c]) return 0;

        // è l'elemento che ho tolto nel loop precedente, non serve controllare 
        if(tolto == S[r][i]-48) return 0;
    }

    // siamo alla fine della linea

    // controlla che sia valido l'elemento in cui ti trovi
    if(colonne[i] != 1 && S[r][i] != S[r][c]) return 0;

    // ottimizzazione
    // in questo loop non ho ancora tolto nessun sacchetto
    if(tolto_temp == -1) tolto_temp = S[r][c] - 48;
    // ho tolto sia 1 che 0 (entrambi i sacchetti)
    else if (tolto_temp != S[r][c]) tolto_temp = 2;

    return 1;
}

int pulisci(int N, int M, vector<string> S) {
    n_righe = N;
    n_colonne = M;
    
    int righe[N] = {}, colonne[M] = {};
    int c_r = 1, c_c = 1, ri = 0, ci = 0, temp_c, temp_r;
    tolto = -1, tolto_temp = -1;

    while(c_r == 1 || c_c == 1) {
        // copio le variabili, mi servono per risparmiare tempo. Se ho tolto solo righe controllo solo le colonne e viceversa
        temp_c = c_c;
        temp_r = c_r;

        // reset variabili di controllo
        c_r = 0, c_c = 0;

        // variabile di controllo per trovare la prima riga / colonna agibile
        int controllo = 0;

        // ho tolto almeno una colonna nel loop precedente, controllo le righe
        if(temp_c == 1) {
            for(int i=ri; i<N; i++) {
                // conotrollo che quetsa riga non sia già eliminata
                if(righe[i] == 1) continue;

                // controllo se = 1 ho tolto la riga, faccio update
                if(check_riga(N, M, i, ci, S, colonne) == 1) {
                    righe[i] = 1;

                    // questa variabile è = 0 all'inizio del loop e cambia solo
                    // se sposto almeno un sacchetto
                    c_r = 1;
                    n_righe -= 1;
                }
                // prendo la prima riga agibile, da utilizzare nel prossimo loop
                else if(controllo == 0) {
                    ri = i;
                    controllo = 1;
                }
            }
        }
        
        // variabile di controllo per trovare la prima riga / colonna agibile
        controllo = 0;
        // ho tolto almeno una riga nel loop precedente, controllo le colonne
        if(temp_r == 1) {
            for(int h=ci; h<M; h++) {
                // conotrollo che quetsa colonna non sia già eliminata
                if(colonne[h] == 1) continue;

                // controllo se = 1 ho tolto la colonna, faccio update
                if(check_colonna(N, M, ri, h, S, righe) == 1) {
                    colonne[h] = 1;

                    // copio in questa variabile, che è = 0 all'inizio del loop e cambia solo
                    // se sposto almeno un sacchetto
                    c_c = 1;
                    n_colonne -= 1;
                }
                else if(controllo == 0) {
                    ci = h;
                    controllo = 1;
                }
            }
        }

        // salvo la variabile per il loop successivo
        tolto = tolto_temp;
    }   
    
    return (n_righe * n_colonne);
}

Prendi in considerazione anche il secondo consiglio:

cioè un vettore di contatori degli uni di ogni riga ed uno di ogni colonna.

Avevo capito male il secondo consiglio. Ora fa 100/100, grazie mille.
Includo il codice, penso possa essere utile nel caso in cui qualcuno in futuro avesse il mio stesso problema.

#include <bits/stdc++.h>

using namespace std;

int n_righe, n_colonne;

int init(int N, int M, int righe_counter[], int colonne_counter[], vector<string> &S) {
    // inizializzo i vettori counter, contano quanti 1 ci sono in una riga / colonna
    for(int i=0; i<N; i++) {
        for(int j=0; j<M; j++) {
            if(S[i][j] == '1') {
                righe_counter[i] += 1;
                colonne_counter[j] += 1;
            }
        }
    }
    return 0;
}

int check_colonna(int N, int c, int colonne_counter[], int righe_counter[]) {
    if(n_righe == colonne_counter[c]) {  // in questa colonna ci sono solo 1
        // sto togliendo uno da ogni riga
        for(int i=0; i<N; i++) righe_counter[i] -= 1;
        return 1;
    }
    if(colonne_counter[c] == 0) {  // in questa colonna ci sono solo 0
        return 1;
    }

    return 0;
}

int check_riga(int M, int r, int colonne_counter[], int righe_counter[]) {
    if(n_colonne == righe_counter[r]) {  // in questa riga ci sono solo 1
        // sto togliendo uno da ogni colonna
        for(int i=0; i<M; i++) colonne_counter[i] -= 1;
        return 1;
    }
    if(righe_counter[r] == 0) {  // in questa colonna ci sono solo 0
        return 1;
    }

    return 0;
}

int pulisci(int N, int M, vector<string> S) {
    n_righe = N;
    n_colonne = M;
    
    int righe[N] = {}, colonne[M] = {}, righe_counter[N] = { }, colonne_counter[M] = { };
    int c_r = 1, c_c = 1, ri = 0, ci = 0, temp_c, temp_r;

    init(N, M, righe_counter, colonne_counter, S);

    while(c_r == 1 || c_c == 1) {
        // copio le variabili, mi servono per risparmiare tempo. Se ho tolto solo righe controllo solo le colonne e viceversa
        temp_c = c_c;
        temp_r = c_r;

        // reset variabili di controllo
        c_r = 0, c_c = 0;

        // variabile di controllo per trovare la prima riga / colonna agibile
        int controllo = 0;

        // ho tolto almeno una colonna nel loop precedente, controllo le righe
        if(temp_c == 1) {
            for(int i=ri; i<N; i++) {
                // conotrollo che quetsa riga non sia già eliminata
                if(righe[i] == 1) continue;

                // controllo se = 1 ho tolto la riga, faccio update
                if(check_riga(M, i, colonne_counter, righe_counter) == 1) {
                    righe[i] = 1;

                    // questa variabile è = 0 all'inizio del loop e cambia solo
                    // se sposto almeno un sacchetto
                    c_r = 1;
                    n_righe -= 1;
                }
                // prendo la prima riga agibile, da utilizzare nel prossimo loop
                else if(controllo == 0) {
                    ri = i;
                    controllo = 1;
                }
            }
        }
        
        // variabile di controllo per trovare la prima riga / colonna agibile
        controllo = 0;
        // ho tolto almeno una riga nel loop precedente, controllo le colonne
        if(temp_r == 1) {
            for(int h=ci; h<M; h++) {
                // conotrollo che quetsa colonna non sia già eliminata
                if(colonne[h] == 1) continue;

                // controllo se = 1 ho tolto la colonna, faccio update
                if(check_colonna(N, h, colonne_counter, righe_counter) == 1) {
                    colonne[h] = 1;

                    // copio in questa variabile, che è = 0 all'inizio del loop e cambia solo
                    // se sposto almeno un sacchetto
                    c_c = 1;
                    n_colonne -= 1;
                }
                else if(controllo == 0) {
                    ci = h;
                    controllo = 1;
                }
            }
        }

    }   
    
    return (n_righe * n_colonne);
}```