Rezolvare completă PbInfo #1785 MZ

Fericit că s-a calificat la ONI, XORin vrea să sărbătorească făcând cât mai mult zgomot. Deoarece e programator, acesta s-a gândit să automatizeze felul în care face zgomot. 

Pentru a face zgomot el folosește o placă cu circuite de diverse intensități. Placa poate fi reprezentată sub forma unei matrice cu N linii și M coloane. Fiecare celulă din matrice are o intensitate între 0 și 9 (o celulă cu intensitatea 0 corespunde unei zone goale, fără nici un circuit).

Un circuit începe într-o celulă a matricei și se termină în altă celulă, fiind o succesiune de celule adiacente de aceeași intensitate de la un capăt la celălalt al circuitului, asemenea unui drum pe matrice între cele două celule. Două celule se consideră adiacente dacă au o latură comună, deci o celulă e adiacentă cu maxim patru alte celule.

Placa a fost concepută în așa fel încât să nu apară scurtcircuite, așadar curentul dintr-un circuit poate merge numai într-o singură direcție (cu alte cuvinte, fiecare celulă dintr-un circuit se învecinează cu maxim alte două celule din același circuit). Nu există circuite de aceeași intensitate care să se învecineze.

Zgomotul produs de un circuit este egal cu lungimea lui, adică cu numărul de celule din matrice corespunzătoare circuitului.

Exemple de circuite invalide: 

03    111 
33    110 
33    110 
040 
444 
040 
Circuitele pot să se scurtcircuiteze. Circuitul nu are exact două capete. 

Cerințe

1) Să se afle numărul de circuite. 
2) Să se afle valoarea zgomotului maxim care poate fi obținut unind două circuite. Două circuite pot fi unite dacă se poate trage o legătură de la un capăt al unui circuit până la un capăt al celuilalt circuit, numai prin celulele libere ale matricei (de intensitate 0). Legătura trebuie să aibă forma unui circuit. Lungimea circuitului nou creat nu se adaugă la zgomotul produs de cele doua circuite. 
3) Să se afișeze placa ce conține legătura care unește două circuite din care se obține zgomotul maxim de la cerința 2. Dacă există mai multe variante, se poate afișa orice placă care conține legătura validă. 

Date de intrare

Pe prima linie a fișierului mz.in se vor afla N și M, lungimea și lățimea plăcii. Pe urmatoarele N linii se vor afla M numere care vor caracteriza intensitatea circuitului care trece prin celula respectivă. În cazul în care prin celula respectivă nu trece un circuit, în fișier se va afla caracterul 0.

Date de ieșire

Prima linie a fișierului mz.out va conține pe prima linie numărul de circuite. 
A doua linie va conține lungimea maximă a unui circuit care poate fi obținut unind două circuite. 
Pe următoarele linii se va afișa matricea care conține circuitul nou format. Fiecare celulă din legătură prin care trece circuitul va fi marcată prin caracterul x.

Restricții și precizări

  • 1 <= N, M <= 1000 pentru toate testele. 
  • 1 <= N * M <= 2500 pentru 20% din teste. 
  • 1 <= N * M <= 10000 pentru 40% din teste. 
  • Se garantează existența a cel puțin 2 circuite care pot fi unite. 
  • Două circuite pot fi unite doar prin capetele lor (capetele legăturii dintre circuite trebuie să fie adiacente cu câte un capăt al fiecărui circuit unit). 
  • Două circuite nu pot fi unite decât prin zone libere (legătură se poate forma doar pe celule de intensitate 0). 
  • În cazul în care există mai multe soluții la cerința 3, se va afișa oricare dintre ele. 
  • Pentru rezolvarea corectă a cerinței (1) se primește 20% din punctaj.  
  • Pentru rezolvarea corectă a cerințelor (1) și (2) se primește 50% din punctaj. 
  • Pentru rezolvarea corectă a tuturor celor 3 cerințe se primește 100% din punctaj. 

Exemplul 1

mz.in

8 6 
122100 
111100 
000000 
000011 
222221 
000011 
000000 
333000 

mz.out

5 
11 
1221x0 
1111x0 
000xx0 
xxxx11 
222221 
000011 
000000 
333000 

Exemplul 2

mz.in

4 20 
00000000000010000000 
00000000000010000000 
00000000000100000000 
00000000001000000000 

mz.out

3 
3 
00000000000x10000000 
0000000000xx10000000 
0000000000x100000000 
00000000001000000000 

Exemplul 3

mz.in

8 25 
0000000000000000000000000 
0000001110001010011000000 
0000010001110101100100000 
0000001000000100001000000 
0000110000000000000100000 
2111000011000000000010000 
0001000000000010000012000 
0001000000000000000000100

mz.out

20 
8 
00000xxxxxxx0000000000000 
0000xx11100x1010011000000 
0000x10001110101100100000 
000xx01000000100001000000 
0xxx110000000000000100000 
2111000011000000000010000 
0001000000000010000012000 
0001000000000000000000100 

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 MZ:

#include <iostream>
#include <iomanip>
#include <fstream>
#include <vector>
#include <set>
#include <queue>
#include <algorithm>
#define DN 1005
#define x first
#define y second
using namespace std;
  
typedef pair<int,int> per;
  
int n,m,viz[DN][DN],nz,len[DN][DN],nrc,r2;
int dx[]={0,1,0,-1},dy[]={1,0,-1,0};
string mt[DN];
vector<pair<int,per> > z;
per a,b;
  
int ins(int a,int b) {
  return a>=0 && b>=0 && a<n && b<m;
}
  
//pot sa am segm de lungime 1
int ie(int a,int b) {
  int sim=0;
  for(int d=0; d<4; ++d) {
    int aa=a+dx[d],bb=b+dy[d];
    if(ins(aa,bb) && mt[aa][bb]==mt[a][b]) ++sim;
  }
  return sim<2;
}
  
set<per> s;
vector<per> cp,_cp[DN][DN];
  
int lg;
void getLen(int a,int b) {
  if(s.find(make_pair(a,b))!=s.end()) return;
  if(len[a][b]) {
    lg=len[a][b];
    s.insert(_cp[a][b].front()); s.insert(_cp[a][b].back());
    return;
  }
  if(ie(a,b)) {
    cp.push_back(make_pair(a,b));
    s.insert(make_pair(a,b));
  }
  ++nrc;
  ++lg;
  viz[a][b]=1;
  for(int d=0; d<4; ++d) {
    int aa=a+dx[d],bb=b+dy[d];
    if(ins(aa,bb) && mt[aa][bb]==mt[a][b] && !viz[aa][bb]) {
      getLen(aa,bb);
      --nrc;
    }
  }
  len[a][b]=lg;
}
  
void df(int a,int b) {
  viz[a][b]=1;
  for(int d=0; d<4; ++d) {
    int aa=a+dx[d],bb=b+dy[d];
    if(!ins(aa,bb)) continue;
    if(mt[aa][bb]!='0' && ie(aa,bb)) {
      lg=0; cp.clear();
      getLen(aa,bb);
      if(cp.size()) {
        per a=cp.front(), b=cp.back();
        _cp[a.x][a.y].push_back(a); _cp[a.x][a.y].push_back(b);
        _cp[b.x][b.y].push_back(a); _cp[b.x][b.y].push_back(b);
      }
      if(lg) {
        z.push_back(make_pair(lg,make_pair(a,b)));
        //cout<<a<<' '<<b<<' '<<lg<<'\n';
      }
    }
    if(mt[aa][bb]=='0' && !viz[aa][bb]) df(aa,bb);
  }
}
  
int px[DN][DN],py[DN][DN];
void bf() {
  queue<per> c;
  px[a.x][a.y]=py[a.x][a.y]=-1;
  int ok=0;
  for(c.push(a);!c.empty() && !ok;) {
    per fr=c.front(); c.pop();
    //cerr<<fr.x<<' '<<fr.y<<'\n';
    for(int d=0; d<4; ++d) {
      per nx=make_pair(fr.x+dx[d],fr.y+dy[d]);
      if(ins(nx.x,nx.y) && px[nx.x][nx.y]==0 && mt[nx.x][nx.y]=='0') {
        px[nx.x][nx.y]=fr.x+1;
        py[nx.x][nx.y]=fr.y+1;
        c.push(make_pair(nx.x,nx.y));
        if(nx==b) {
          ok=1;
          break;
        }
      }
    }
  }
  for(;px[b.x][b.y]!=-1;) {
    mt[b.x][b.y]='x';
    b=make_pair(px[b.x][b.y]-1,py[b.x][b.y]-1);
  }
  mt[a.x][a.y]='x';
}
  
  
int main() {
  ifstream f("mz.in");
  ofstream g("mz.out");
  f>>n>>m;
  for(int i=0; i<n; ++i) f>>mt[i];
  for(int i=0; i<n; ++i) for(int j=0; j<m; ++j) if(!viz[i][j] && mt[i][j]=='0') {
    df(i,j);
    //cout<<i<<' '<<j<<'\n';
    sort(z.rbegin(),z.rend());
    if(z.size()>1 && r2<z[0].first+z[1].first) {
      r2=z[0].first+z[1].first;
      a=z[0].second; b=z[1].second;
      //cout<<a.x<<' '<<a.y<<' '<<b.x<<' '<<b.y<<' '<<r2<<'\n';
    }
    ++nz;
    s.clear();
    z.clear();
    //cout<<"clear\n";
  }
  for(int i=0; i<n; ++i) {
    for(int j=0; j<m; ++j) {
      lg=0;
      if(!viz[i][j] && ie(i,j)) getLen(i,j);
      //cout<<fixed<<setw(3)<<len[i][j];
    }
    //cout<<'\n';
  }
  bf();
  g<<nrc<<'\n'<<r2<<'\n';
  for(int i=0; i<n; ++i) g<<mt[i]<<'\n';
}

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 #1785 MZ

Pe această pagină găsești rezolvarea de 100 de puncte pentru problema #1785 MZ 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!