Cod sursa(job #3030720)

Utilizator chiriacandrei25Chiriac Andrei chiriacandrei25 Data 17 martie 2023 20:29:29
Problema Jocul Flip Scor 0
Compilator cpp-64 Status done
Runda Arhiva de probleme Marime 2.59 kb
/*
1 ≤ N, M ≤ 16 => O(2^n * n * m) => Backtracking
Backtracking = algoritm care genereaza toate variantele posibile
Exemple: Generare de permutari, Submultimi, ...
Flip: Care ar fi toate variantele posibile? => Toate posibilitatile de a flipui
linii si coloane.
L1L3L5L8C2C4C6 <=> L1C2L3L5C4L8C6
Fiecare linie / coloana are 2 posibilitati: flip sau no flip
Toate posibilitatile = Orice submultime de linii si coloane
{L1, L2, L3, L4, C1, C2, C3}:
1) {L1, L4, C2} => suma1
2) {L2, L3, C1} => suma2
3) {C1, C2} => suma3
...
O multime cu n elemente are exact 2^n submultimi distincte.
{1, 2, 3}
000 => {}
001 => {3}
010 => {2}
011 => {2, 3}
100 => {1}
101 => {1, 3}
110 => {1, 2}
111 => {1, 2, 3}

{1, 2, 3, ..., n} => 2 * 2 * ... * 2 => 2^n

Nu intra O(2^(n + m)) dar intra O(2^n * n * m) => Intra in timp sa generez
toate submultimile posibilie de linii / sau coloane (DOAR UNA)

Pt fiecare submultime de linii => flip liniile alea => flip coloanele negative
*/

#include <fstream>
#include <vector>
#include <cmath>

using namespace std;

// Backtracking e despre decizii. Deciziile sunt ca pentru fiecare linie de la 1 la n
// sa decidem daca o adaugam in submultime sau nu

vector<int> submultime;
int n, m, a[20][20], sol = -INT_MAX;

void flip_line(int line) {
    for(int col = 1; col <= m; col++) {
        a[line][col] *= -1;
    }
}

void backtracking(int lin) {
    // Punct de oprire:
    if (lin == n + 1) {
        // Submultimea e generata. Hai sa aflam solutia pt aceasta submultime
        for(int linie : submultime) {
            flip_line(linie);
        }
        
        int total = 0;
        for(int col = 1; col <= m; col++) {
            int sum_col = 0;
            for(int lin = 1; lin <= n; lin++) {
                sum_col += a[lin][col];
            }
            total += abs(sum_col);
        }
        sol = max(sol, total);

        for(int linie : submultime) {
            flip_line(linie);
        }
        return;
    }
    // Decizii:
    // Caz 1: adaug linia lin in submultime:
    submultime.push_back(lin);
    backtracking(lin + 1); // imi genereaza toate submultimile care contin linia 1
    // Caz 2: nu adaug linia lin:
    submultime.pop_back();
    backtracking(lin + 1); // imi genereaza toate submultimile care nu contin linia 1
}

int main() {
    ifstream fin("flip.in");
    ofstream fout("flip.out");
    fin >> n >> m;
    for(int i = 1; i <= n; i++) {
        for(int j = 1; j <= m; j++) {
            fin >> a[i][j];
        }
    }
    backtracking(1);
    fout << sol << "\n";
    return 0;
}