Rezolvare completă PbInfo #1830 Armata Regelui

În Regatul din Sud nu e niciodată prea devreme să te pregăteşti de război. De aceea, în fiecare an Regele organizează un concurs în care premiaţi sunt cei mai buni strategi. Mai întâi, Strategul Şef alege configuraţia ideală de razboi, în care armata va fi dispusă. O trupă într-o configurație e reprezentată de o literă mica din mulțimea {'a'..'z'}. De exemplu, configuraţia “ffscaam" descrie o armată formată din doi fermieri, un soldat, un cavaler, doi arcaşi şi un mag. Bineînţeles, în timpul unei lupte, trupele nu îşi vor menţine neapărat poziiţile inţiale. Cu toate acestea, orice tip de trupă poate schimba poziţia cu maxim un alt tip de trupă, ştiut de dinainte de toţi locuitorii regatului. De asemenea se ştie că arcaşii nu schimbă poziţii decât între ei. Pentru exemplul anterior, dacă un fermier sau un soldat nu schimbă poziţii decât cu un alt fermier sau soldat, configuraţii echivalente cu “ffscaam" sunt “fsfcaam" şi “sffcaam".

Fiecare strateg concurent alege o configuraţie, iar câştigătorii sunt cei care aleg configuraţii echivalente cu cea a Strategului Şef.

Cerința

Date fiind configuraţia Strategului Şef, M perechi de trupe care comută, şi cele N configuraţii ale concurenţilor, numerotate de la 1 la N, să se afişeze indecşii configuraţiilor câştigătoare.

Date de intrare

Fişierul armata_regelui.in va conţine pe prima linie configuraţia Strategului Şef, pe a doua linie M şi N, pe următoarele M linii perechile de trupe care comută, separate printr-un spaţiu, iar pe următoarele N linii cele N configuraţii concurente, fiecare pe câte o linie.

Date de ieșire

Fişierul armata_regelui.out va conţine, în ordine crescătoare, indecşii configuraţiilor câştigătoare, fiecare pe câte o linie.

Restricții și precizări

  • M < 7
  • N < 5001
  • Lungimea unei configuraţii < 5001
  • Fiecare test conţine < 151 configuraţii câştigătoare
  • Toate testele conţin arcaşi. Cel putin 2 teste au < 20 arcaşi. Arcaşii sunt mereu reprezentaţi de litera 'a' şi sunt în general mai puţini decât celelalte trupe. Dacă \(t_1\) comută cu \(t_2\) atunci şi \(t_2\) comută cu \(t_1\).

Exemplu

armata_regelui.in

ffscaam
6 6
f s
c m
b g
d z
x y
l t
ffsacam
ffscaam
fsfcaam
sffcaam
scmaafssf
ffztacm

armata_regelui.out

2
3
4

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 Armata Regelui:

// autor: Iulia Tamas
#include <fstream>
#include <string.h>
#include <assert.h>

#include <string>
#include <set>
#include <vector>
using namespace std;

#define A_SIZE 26 // alfabet
#define t_interval pair<pair<char, int>, pair<char, int> >
#define t_intervals vector<t_interval>
#define t_intervals_it vector<t_interval>::iterator

char comuta_cu[A_SIZE];
int ss_count[A_SIZE]; // numarul de litere de fiecare fel din ss_config
set<char> ss_in; // literele (trupele) din ss_config
set<int> ss_arc; // pozitiile arcasilor in ss_config
t_intervals ss_ivls;

int count[A_SIZE]; // numarul de litere din config curenta

void next_interval(string config, int clen, int *start, t_intervals &ivls) {
  if (*start >= clen)
    return;

  // calculam descrirea intervalui format doar din literele lit si c_lit
  char lit = config[*start];
  char c_lit = comuta_cu[lit - 'a'];
  int i, n_lit, n_c_lit;
  n_lit = 0; // numar de aparitii litera
  n_c_lit = 0; // numar de aparitii litera care comuta
  for(i = *start; i < clen; i++) {
    if(config[i] == lit) {
      n_lit++;
      continue;
    }
    if(config[i] == c_lit) {
      n_c_lit++;
      continue;
    }
    break;
  }

  ivls.push_back(make_pair(make_pair(lit, n_lit), make_pair(c_lit, n_c_lit)));
  *start = i;
}

bool equal_intervals(t_interval a, t_interval b) {
  return (a.first == b.first && a.second == b.second) ||
         (a.first == b.second && a.second == b.first);
}

// Prespune: config de lungime corecta
bool same_arc(const string &config) {
  set<int>::iterator it;
  for(it = ss_arc.begin(); it != ss_arc.end(); it++){
    if(config[*it] != 'a')
      return false;
  }
  return true;
}

bool same_troups(const string &config) {
  memset(count, 0, A_SIZE * sizeof(int));
  string::const_iterator sit;
  for (sit = config.begin(); sit != config.end(); sit++) {
    if (++count[*sit - 'a'] > ss_count[*sit - 'a'])
      return false;
  }
  return true;
}

int main() {
  fstream fin, fout;
  fin.open("armata_regelui.in", fstream::in);
  fout.open("armata_regelui.out", fstream::out);

  // ss_config
  string ss_config;
  fin >> ss_config;
  int ss_len = ss_config.size();

  // precalculari litere in ss_config
  char lit;
  string::iterator sit;
  memset(comuta_cu, 0, A_SIZE);
  memset(ss_count, 0, A_SIZE * sizeof(int));
  ss_in.clear();
  ss_arc.clear();
  for (sit = ss_config.begin(); sit != ss_config.end(); sit++) {
    lit = *sit;
    assert(lit >= 'a' && lit <= 'z');

    ss_count[lit - 'a']++;
    ss_in.insert(lit);
    if (lit == 'a') ss_arc.insert(sit - ss_config.begin());
  }

  // perechi care comuta
  int M, N;
  char t1, t2;
  fin >> M >> N;
  for(int i = 0; i < M; i++) {
    fin >> t1 >> t2;
    comuta_cu[t1 - 'a'] = t2;
    comuta_cu[t2 - 'a'] = t1;
  }

  // precalculari intervale in ss_config
  int start = 0;
  do {
    next_interval(ss_config, ss_len, &start, ss_ivls);
  } while(start < ss_len);

  // verificam fiecare configuratie
  string config;
  t_intervals ivls;
  t_intervals_it iit;
  for(int i = 1; i <= N; i++){
    fin >> config;
    int c_len = config.size();
    if (c_len != ss_len){
      continue;
    }

    // verificam pozitiile arcasilor
    if (!same_arc(config)){
      continue;
    }

    // verificam numar din fiecare trupa
    if (!same_troups(config)){
      continue;
    }

    // verificam fiecare interval in parte
    ivls.clear();
    start = 0;
    iit = ss_ivls.begin();
    do {
      next_interval(config, c_len, &start, ivls);
      if(!equal_intervals(ivls.back(), *iit)) {
        break;
      }

      iit++;
    } while(start < c_len && iit != ss_ivls.end());

    if(start == c_len && iit == ss_ivls.end()) {
      // acelasi numar de intervale si intervalele sunt identice
      fout << 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 #1830 Armata Regelui

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