Rezolvare completă PbInfo #1041 Biperm

Pentru un număr natural nenul n, să considerăm toate numerele naturale nenule mai mici sau egale cu n, luând fiecare număr de câte două ori: 1, 1, 2, 2, 3, 3, ... , n, n. Aceste numere le amestecăm aleator, şi le aranjăm pe două linii a câte n elemente. Structura astfel obţinută o vom numi o bipermutare. În figurile 1, 2 şi 3 avem câte un exemplu de bipermutare pentru n=5.

O bipermutare este perfectă, dacă ambele linii ale structurii reprezintă câte o permutare (vezi figurile 2 şi 3).

Prin mutare pe poziţia p, înţelegem interschimbarea elementelor de pe aceeaşi coloană p. În exemplele de mai jos, bipermutarea perfectă din figura 2 s-a obţinut din bipermutarea din figura 1, aplicând o mutare pe poziţa 2. Bipermutarea perfectă din figura 3 s-a obţinut din bipermutarea din figura 1, aplicând mutări pe poziţiile 1, 2, 4 şi 5.

Cerința

Cunoscând o bipermutare, determinaţi:

  • numărul bipermutărilor perfecte distincte ce se pot obţine prin mutări;
  • numărul minim de mutări prin care se poate obţine o bipermutare perfectă;
  • o bipermutare perfectă obţinută din bipermutarea iniţială.

Date de intrare

Fișierul de intrare biperm.in conține pe prima linie valoarea lui n. Următoarele două linii conţin, fiecare, câte n elemente separate prin câte un spaţiu, formând o bipermutare.

Date de ieșire

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

  • pe prima linie două numere naturale separate printr-un spaţiu, reprezentând numărul bipermutărilor perfecte distincte ce se pot obţine din bipermutarea dată, respectiv numărul minim de mutări prin care se poate obţine o bipermutare perfectă;
  • pe următoarele două linii se vor tipări câte n numere separate prin spaţiu, reprezentând o bipermutare perfectă obţinută din bipermutarea dată.

Restricții și precizări

  • 2 < n ≤ 10 000;
  • calculul corect al numărului bipermutărilor perfecte distincte valorează 30% din punctaj;
  • calculul corect al numărului minim de mutări valorează 10% din punctaj;
  • tipărirea unei bipermutări perfecte valorează 60% din punctaj. Pot exista mai multe soluţii, se va admite orice soluţie corectă;
  • se garantează că numărul bipermutărilor perfecte distincte nu depăşeşte 2 000 000 000 pentru niciun test.
  • pentru 40% din teste n ≤ 20
  • pentru 40% din teste 20 < n ≤ 400
  • pentru 20% din teste 400 < n ≤ 10 000

Exemplu

biperm.in

5
1 5 5 3 4
3 2 2 4 1

biperm.out

4 1
1 2 5 3 4
3 5 2 4 1

Explicație

Sunt 4 permutări perfecte. Numărul minim de mutări este 1 şi există două soluţii cu număr minim de mutări:

1 2 5 3 4            1 5 2 3 4
3 5 2 4 1     şi      3 2 5 4 1

Celelalte două soluţii, ce nu se obţin din număr minim de mutări sunt:

3 2 5 4 1            3 5 2 4 1
1 5 2 3 4     şi      1 2 5 3 4

Pentru a treia cerinţă oricare dintre cele 4 soluţii este acceptată.

Cum e corect?

cout < "As la info"; cout << "As la info"; cout >> "As la info";

Felicitări! Poți mai mult?

Avem sute de probleme pentru tine, fiecare cu explicații ușor de înțeles.

Greșit, dar nu-i bai!

Antrenează-te cu sutele de probleme pe care ți le-am pregătit. Îți explicăm fiecare problemă în parte.

Rezolvare

Iată rezolvarea de 100 de puncte pentru problema Biperm:

// prof. Szabo Zoltan - Mures
// 100 puncte
#include <fstream>
#include <iostream>

using namespace std;
int viz[2][10003],a[2][10003],b[2][10003];
int main()
{   int n,i,j,p,nrmin,invers,l,poz,ant,aux,urmviz;
    ifstream fin("biperm.in");
    ofstream fout("biperm.out");
    fin>>n;
    for (i=0;i<2;++i)                  // matricea viz[x][i] are semnificatia:
        for (j=1;j<=n;++j)
        {
            fin>>a[i][j];              // numarul i apare in bipermutare pe pozitiile
            if (viz[0][a[i][j]]==0)    //           viz[0][i]  si viz[1][i]
                viz[0][a[i][j]]=j;
            else
                viz[1][a[i][j]]=j;
        }
    p=1;           // p - numarul solutiilor distincte, produs, putere a lui 2
    nrmin=0;      // nrmin - va numara interschimbarile efectuate pentru cazul optim
    for (i=1;i<=n;++i)
        if (b[0][i]==0)
        {   l=1; invers=0;poz=i;    // reconstruim ciclurile: l lungimea ciclului
                                    // invers= cate arce sunt in ciclu cu sensul invers
            b[0][poz]=a[0][poz];    // poz = pozitia curenta in ciclu
            b[1][poz]=a[1][poz];    // ant = pozitita anterioara in ciclu
            ant=poz;                // in b se construieste permutarea dubla ceruta
            urmviz=b[1][poz];        // urmatorul nod spre vizitare in lant
            if (viz[0][urmviz]==poz)   //
                poz=viz[1][urmviz];
            else
                poz=viz[0][urmviz]; // lant continua este muchia a[0][poz] si a[1][poz]
            while (!b[0][poz])
            {
                if (a[0][poz]==b[1][ant])
                {
                    b[0][poz]=a[0][poz];
                    b[1][poz]=a[1][poz];
                    l++;
                    ant=poz;
                    urmviz=b[1][poz];
                    if (viz[0][urmviz]==poz)
                        poz=viz[1][urmviz];
                    else
                        poz=viz[0][urmviz];
                }
                else
                {
                    b[0][poz]=a[1][poz];
                    b[1][poz]=a[0][poz];
                    l++;invers++;          // am gasit un nou arc invers
                    ant=poz;               //
                    urmviz=b[1][poz];
                    if (viz[0][urmviz]==poz)
                        poz=viz[1][urmviz];
                    else
                        poz=viz[0][urmviz];
                }

            }
            if (l>1)
                p*=2;
            if (invers>l-invers)
                nrmin+=l-invers;
            else
                nrmin+=invers;
        }
    fout<<p<<" "<<nrmin<<"
";
    for(i=0;i<2;++i)
    {   for(j=1;j<n;++j)
            fout<<b[i][j]<<" ";
        fout<<b[i][n]<<"
";
    }
    fin.close();
    fout.close();
    return 0;
}

Atenție

Enunțurile afișate pe această pagină aparțin exclusiv site-ului PbInfo. Astfel, pentru ștergerea conținutului, puteți să ne contactați la adresa Adresa de email.

Rezolvarea problemei #1041 Biperm

Pe această pagină găsești rezolvarea de 100 de puncte pentru problema #1041 Biperm de pe PbInfo.ro. Atenție: nu încurajăm copiatul codului! Totuși, credem cu tărie că analizarea unei soluții corecte este o metodă foarte ușoară de a învăța informatică, astfel că oferim sursele pentru peste 1500 de probleme de pe platforma PbInfo.ro.

Pentru rezolvări PbInfo de la peste 1500 de probleme, vă invităm să intrați pe site-ul nostru!