# PBinfo #1032 – Compresie – Rezolvare C++

Sursa: Codul lui Andrei
Limbaj: C++
Autor rezolvare: deivid

## Enunț

Se consideră un text memorat într-o matrice M, definită prin coordonatele colţului stânga sus (x1,y1) şi coordonatele colţului dreapta jos (x2,y2).

Prin aplicarea unui algoritm de compresie, matricei M i se asociază un şir de caractere, notat CM. Şirul de caractere CM  este construit prin aplicarea următoarelor reguli:


dacă matricea M are o singură linie şi o singură coloană atunci CM conţine numai caracterul memorat în matrice;
dacă toate elementele matricei sunt identice atunci întreaga matrice M se comprimă şi CM este şirul kc, unde k reprezintă numărul de caractere din matrice, iar c caracterul memorat;
dacă matricea este formată din caractere diferite şi are cel puţin două linii şi două coloane atunci:
	
 matricea este împărţită în 4 submatrice A, B, C, D după cum este ilustrat în figura alăturată, unde coordonatele colţului stânga sus ale submatricei A sunt (x1,y1), iar coordonatele colţului dreapta jos sunt ((x2+x1)/2,(y2+y1)/2);
CM este şirul *CACBCCCD  unde CA, CB, CC, CD sunt şirurile de caractere obţinute, în ordine, prin compresia matricelor A, B, C, D utilizând acelaşi algoritm;

dacă matricea este formată din caractere diferite, are o singură linie şi mai multe coloane atunci CM este şirul *CACB  unde A, B, CA, CB au semnificaţia descrisă la punctul 3.;
dacă matricea este formată din caractere diferite, are mai multe linii şi o singură coloană atunci CM este şirul *CACC  unde A, C, CA, CC au semnificaţia descrisă la punctul 3.;

Cerinţă
Dat fiind şirul de caractere CM ce se obţine în urma aplicării algoritmului de compresie asupra unei matrice M de dimensiune NxN să se determine: 


numărul de împărţiri care au fost necesare pentru obţinerea textului compresat;
matricea iniţială din care provine textul compresat.

Date de intrare
Fișierul de intrare compresie.in conţine pe prima linie un şir de caractere ce reprezintă textul compresat.

Date de ieșire
Fișierul de ieșire compresie.out va conține:


pe prima linie un număr natural ce reprezintă  numărul  nr de împărţiri care au fost necesare pentru obţinerea textului compresat;
pe următoarele N linii se găsesc câte N caractere, litere mici ale alfabetului englez, neseparate prin spații, ce reprezintă, în ordine, liniile matricei iniţiale.

Restricții și precizări

2 ≤ N ≤ 1000
0 ≤ nr ≤ 1000000
2 ≤ lungimea şirului compresat ≤ 1000000
Textul memorat iniţial în matricea M conţine numai caractere din mulţimea literelor mici {a...z}.

Exemplul 1
compresie.in

*4b*bbab4a*abbb
compresie.out

3 
bbbb
bbab
aaab
aabb
Explicație
Au fost efectuate 3 împărţiri:


\( M = * \left( \begin{array}{cc}
b & b  \\
b & b \end{array} \right)
\left( \begin{array}{cc}
b & b  \\
a & b \end{array} \right)
\left( \begin{array}{cc}
a & a  \\
a & a \end{array} \right)
\left( \begin{array}{cc}
a & b  \\
b & b \end{array} \right)
  \)
\( 
\left( \begin{array}{cc}
b & b  \\
a & b \end{array} \right)
= * (b)(b)(a)(b)
 \)
\( 
\left( \begin{array}{cc}
a & b  \\
b & b \end{array} \right)
= * (a)(b)(b)(b)
 \)

Exemplul 2
compresie.in

*4a*ab*aba
compresie.out

3 
aaa
aab
aba
Explicație
Au fost efectuate 3 împărţiri:


\( M = * \left( \begin{array}{cc}
a & a  \\
a & a \end{array} \right)
\left( \begin{array}{c}
a  \\
b \end{array} \right)
\left( \begin{array}{cc}
a & b \end{array} \right)
\left( \begin{array}{c}
a \end{array} \right)
  \)
\( 
\left( \begin{array}{c}
a  \\
b \end{array} \right)
= * (a)(b)
 \)
\( 
\left( \begin{array}{cc}
a & b \end{array} \right)
= * (a)(b)
 \)

## Cod sursă C++

```cpp
/*
    Solutie prof. Eugen Nodea
    streamuri
*/
# include <fstream>
# include <cmath>
# include <cstring>
using namespace std;
ifstream f("compresie.in");
ofstream g("compresie.out");
char s[1000001];
char M[1001][1001];
int L, N, nr, i, j, k;
void reconstruieste(short x1,short y1, short x2, short y2)
{
    short mx, my, x, i, j;
    //conditia de oprire
    if (x1<=x2 && y1<=y2 && k<L)
    {
        //stapaneste
        if (x1==x2 && y1==y2) M[x1][y1] = s[k++];
        else
            if (s[k]>='0' && s[k] <='9')
                {
                    x = 0;
                    while (s[k]>='0' && s[k]<='9')
                    {
                        x = x*10 + (s[k] - '0');
                        ++k;
                    }
                    //completez submatricea
                    for (i=x1; i<=x2; ++i)
                        for (j=y1; j<=y2; ++j)
                            M[i][j] = s[k];
                    ++k;
                }
        else //s[k] == '*'
            {
                //divide
                mx = (x2 + x1) >> 1; my = (y2 + y1) >> 1;
                ++k;
                // reconstruiesc submatricile A,B,C,D
                reconstruieste(x1, y1, mx, my);          //A
                reconstruieste(x1, my + 1, mx, y2);      //B
                reconstruieste(mx + 1, y1, x2, my);      //C
                reconstruieste(mx + 1, my + 1, x2, y2);  //D
            }
    }
}
int main()
{
    f.getline(s, 1000001);
    f.close();
    L = strlen(s);
    //punctul 1
    k = 0; nr = 0; j = 0;
    for (i=0; i < L; ++i)
        if (s[i] == '*') ++nr;
            else if (s[i]>='0' && s[i]<='9') k = k*10 + (s[i] - '0');
                    else if (s[i]>='a' && s[i]<='z')
                            {
                                if (s[i-1]<'a' && k) j+=k, k=0;
                                else ++j;
                            }
    N = (int) sqrt((double) j);
    g << nr << "\n";
    //punctul 3
    k=0;
    reconstruieste(1,1,N,N);
    for (i=1; i<=N; ++i)
    {
        for (j=1; j<=N; ++j)
            g << M[i][j];
        g << "\n";
    }
    g.close();
    return 0;
}
```

## Resurse

- [Pagina originală](https://codulluiandrei.ro/rezolvari/pbinfo/1032)
- [Sursa C++](https://codulluiandrei.ro/rezolvari/pbinfo/1032/cod.cpp)
- [Sursa pe GitHub](https://raw.githubusercontent.com/codulluiandrei/pbinfo/main/pbinfo-1032/main.cpp)
- [Cursuri de informatică pentru BAC](https://codulluiandrei.ro/academia/info-curs/pachet-cpp/)
