Sunteți pe pagina 1din 17

94 Ghid practic pentru analiza şi proiectarea algoritmilor.

Aplicații în C#

Metoda programării
#5 dinamice
Subsecvența comună de
lungime maximă
Obiective:
1. Exersarea metodei programării dinamice prin implementarea unei
probleme specifice:
 Problema subsecvenţei comune de lungime maximă a două mulțimi de
numere întregi (LCS – Longest Common Subsequence).
2. Verificarea înţelegerii conceptului de rezolvare prin abordarea unor
probleme de dificultate asemănătoare.
Ghid practic pentru analiza şi proiectarea algoritmilor. Aplicații în C# 95

5.1 Subsecvenţa comună de lungime maximă (LCS – Longest Common Subsequence)

Subsecvenţa comună de lungime maximă


Fie două şiruri de numere întregi a şi b de dimensiuni n respectiv m. O
subsecvenţă a unui şir reprezintă o submulţime de elemente din şir
Problemă nu neapărat pe poziţii consecutive. Să se determine cea mai lungă
exemplu subsecvenţă comună şirurilor a şi b. Dacă există mai multe soluţii de
lungime maximă se va afişa doar una dintre ele.
Datele vor fi citite dintr-un fişier ce conţine pe prima linie numărul de
elemente n iar pe a doua linie elementele mulţimii a separate printr-
un spaţiu. Următoarele două linii vor codifica similar şirul b. Fişierul de
ieşire va conţine pe prima linie lungimea subsecvenţei maxime iar pe a
doua elementele subsecvenţei separate prin spaţiu.
Intrare Ieşire
11 4
7 6 5 2 8 2 8 1 4 7 10 6287
7
6921897

Explicaţie. Cea mai lungă subsecvenţă comună are lungimea 4:


7 6 5 2 8 2 8 1 4 7 10
692189 7

Problema se rezolvă prin divizare în subprobleme de dimensiuni mai mici. Anume,


vom nota cu lung[i,j] lungimea celei mai lungi subsecvenţe comune şirurilor
alcătuite din primele i+1 elemente ale lui a şi primele j+1 elemente ale lui b, cu
i=0..n-1 şi j=0..m-1. Cu această notaţie suntem interesaţi de aflarea valorii
lung[n-1,m-1] care reprezintă lungimea celei mai lungi subsecvenţe alcătuite din
primele n elemente ale şirului a şi primele m elemente ale şirului b (sau echivalent,
din întreg şirul a şi întreg şirul b). Problemele de dimensiuni mici pot fi rezolvate
imediat:
1 dacă a[0]  b[0]
lung [0,0]  
0 altfel

1 dacă a[0]  b[ j ]


lung [0, j ]  
lung [0, j  1] altfel
96 Ghid practic pentru analiza şi proiectarea algoritmilor. Aplicații în C#


1 dacă a[i ]  b[0]
lung [i,0]  

lung [i  1,0] altfel

Pentru a calcula lung[i,j] vom reduce problema la dimensiunile i-1 respectiv


j-1 pentru care dispunem deja de valorile lung[i-1,j], lung[i-1,j-1] şi
lung[i,j-1]. Şi anume, pentru a ajunge la subsecvenţa comună primelor i
elemente din a şi primelor j elemente din b, avem trei posibilităţi de înaintare:
1. Primelor i-1 elemente din a le adăugăm a[i] lăsând j neschimbat, ceea ce
face ca lungimea celei mai lungi subsecvenţe comune să fie lung[i-1, j].
2. Primelor j-1 elemente din b le adăugăm b[j] lăsând i neschimbat, ceea ce
face ca lungimea celei mai lungi subsecvenţe comune să fie lung[i,j-1].
3. Primelor i-1 elemente din a mai adăugăm a[i] iar primelor j-1 elemente
din b mai adăugăm b[j], caz în care:
a. Dacă a[i]==b[j] atunci lungimea celei mai lungi subsecvenţe
comune creşte cu 1 faţă de lung[i-1,j-1].
b. În caz contrar, lungimea celei mai lungi subsecvenţe comune este tot
lung[i-1,j-1] întrucât adăugarea la fiecare şir a câte unui element
a[i] respectiv b[j] diferite nu schimbă lungimea totală a celei mai
lungi subsecvenţe comune.

Afişarea subşirului comun se realizează parcurgând matricea lung în sens invers, de la


poziţia [n-1,m-1] spre [0,0]. Vom afişa elementul a[i] dacă a[i]==b[j] şi
vom descreşte valorile indicilor i şi j. Altfel, vom decrementa fie i fie j în funcţie de
valorile lung[i-1,j] respectiv lung[i,j-1] pentru a reconstitui drumul prin
care am ajuns la lung[i,j]. Oprim algoritmul de tipărire când am ajuns la [0,0].
În continuare este prezentată construirea matricei de lungimi pentru exemplul din
problemă.

a/b 7 6 5 2 8 2 8 1 4 7 10
6 0 1 1 1 1 1 1 1 1 1 1
9 0 1 1 1 1 1 1 1 1 1 1
2 0 1 1 2 2 2 2 2 2 2 2
1 0 1 1 2 2 2 2 3 3 3 3
8 0 1 1 2 3 3 3 3 3 3 3
9 0 1 1 2 3 3 3 3 3 3 3
7 1 1 1 2 3 3 3 3 3 4 4
Ghid practic pentru analiza şi proiectarea algoritmilor. Aplicații în C# 97

Afişarea subşirului comun se realizează parcurgând matricea în sens invers, de la


poziţia [n-1,m-1] spre [0,0]:

a/b 7 6 5 2 8 2 8 1 4 7 10
6 0 1 1 1 1 1 1 1 1 1 1
9 0 1 1 1 1 1 1 1 1 1 1
2 0 1 1 2 2 2 2 2 2 2 2
1 0 1 1 2 2 2 2 3 3 3 3
8 0 1 1 2 3 3 3 3 3 3 3
9 0 1 1 2 3 3 3 3 3 3 3
7 1 1 1 2 3 3 3 3 3 4 4

Algoritmul pentru construirea matricei lung este prezentat în continuare.

int[,] LCS(int[] a, int n, int[] b, int m)


1 lung  new int[n,n]
2 *) rezolvăm subproblemele simple
3 lung[0,0]  (a[0] == b[0]) ? 1 : 0
Pseudocod 4 pentru i  1, n – 1 execută
5 dacă a[i] == b[0] atunci lung[i,0]  1
6 altfel lung[i,0]  lung[i-1,0]
7 ■
8 ■
9 pentru j  1, m – 1 execută
10 dacă a[0] == b[j] atunci lung[0,j]  1
11 altfel lung[0,j]  lung[0,j-1]
12 ■
13 ■
14 *) completăm matricea lung
15 pentru i  1, n – 1 execută
16 pentru j  1, m – 1 execută
17 lung[i, j]  max(
18 (a[i]==b[j])?lung[i-1,j-1]+1:0,
19 lung[i-1, j], lung[i, j-1])
20 ■
21 ■
22 întoarce lung
23 sf.procedură
98 Ghid practic pentru analiza şi proiectarea algoritmilor. Aplicații în C#

Procedura LCS are complexitatea Θ(n)+Θ(m)+Θ(n×m)=Θ(n×m) întrucât operaţia


dominantă este dată de completarea valorilor matricei lung de dimensiune n×m.
Lungimea celei mai lungi subsecvenţe comune celor două şiruri se găseşte la poziţia
[n-1,m-1] în matricea lung. Algoritmul pentru listarea subsecvenţei este prezentat
în continuare.

procedura TipăreşteLCS(
1 int[] a, int n,
2 int[] b, int m,
3 int[,] lung)
Pseudocod 4 scrie „Lungimea maximă:”, lung[n-1,m-1]
5 scrie „Subsecvenţa este:”
6 i  n-1
7 j  m-1
8 cât timp i >= 0 şi j >= 0 execută
9 dacă a[i] == b[j] atunci
10 scrie a[i]
11 i  i-1
12 j  j-1
13 altfel
14 dacă i-1>=0 şi
15 lung[i,j] == lung[i-1,j] atunci
16 i  i-1
17 altfel
18 j  j-1
19 ■
20 ■

sf.procedură

Pentru listarea subsecvenţei comune este necesară parcurgerea matricei de lungimi


parţiale plecând de la poziţia [n-1,m-1] spre [0,0], la fiecare pas decrementând fie
i, fie j, fie ambii indici. Drept urmare, numărul de paşi va fi m+n iar complexitatea
algoritmului TipăreşteLCS va fi Θ(n+m).
Ghid practic pentru analiza şi proiectarea algoritmilor. Aplicații în C# 99

class SubsecventaCrescatoareComuna
{
/// <summary>
/// Calculeaza matricea de lungimi partiale aferenta procedurii de
/// calcul a subsecventei crescatoare comuna sirurilor a si b.
/// </summary>
public static int[,] LCS(int[] a, int[] b)
{
int n = a.Length, m = b.Length;
int[,] lung = new int[n, m];
lung[0, 0] = (a[0] == b[0]) ? 1 : 0;
for (int j = 1; j < m; j++)
lung[0, j] = (a[0] == b[j]) ? 1 : lung[0, j - 1];
for (int i = 1; i < n; i++)
lung[i, 0] = (a[i] == b[0]) ? 1 : lung[i - 1, 0];
for (int i = 1; i < n; i++)
for (int j = 1; j < m; j++)
lung[i, j] = Math.Max(
(a[i] == b[j]) ? lung[i-1, j-1]+1 : lung[i-1, j-1],
Math.Max(lung[i - 1, j], lung[i, j - 1])
);
return lung;
}
/// <summary>
/// Tipareste subsecventa crescatoare comuna subsirurilor a si b.
/// </summary>
public static void TiparesteLCS(int[] a, int[] b, int[,] lung)
{
List<int> subsecventa = new List<int>();
int i = a.Length – 1, j = b.Length - 1;
while (i >= 0 && j >= 0)
{
if (a[i] == b[j])
{
subsecventa.Add(a[i]);
i--; j--;
}
else
if (i >= 1 && lung[i - 1, j] == lung[i, j]) i--;
else if (j >= 1 && lung[i, j - 1] == lung[i, j]) j--;
}
subsecventa.Reverse();
foreach (int x in subsecventa)
Console.Write(x + ", ");
}
}
100 Ghid practic pentru analiza şi proiectarea algoritmilor. Aplicații în C#

5.2 Problema celui mai lung palindrom

Cel mai lung palindrom


Fie un şir de numere întregi de dimensiune n. Să se găsească cea mai
lungă subsecvenţă a acestuia care să fie palindrom (o subsecvenţă
Problemă palindrom afişată în ordine inversă este identică cu subsecvenţa
originală). În cazul în care există mai multe subsecvenţe palindrom de
lungime maximă, va fi afişată una dintre ele la alegere.
Intrare Ieşire
9 5
615378319 13731
Explicație. Cea mai lungă subsecvenţă palindrom are lungimea 5:
615378319

O soluţie simplă de rezolvare constă în aplicarea algoritmului LCS pentru şirul a şi şirul
a inversat. Orice subsecvenţă palindromică va fi o subsecvenţă comună celor două
şiruri iar algoritmul LCS o identifică pe cea mai lungă.

procedura CelMaiLungPalindrom(int[] a, int n)


1 *) construim şirul a inversat
2 a2  new int[n]
3 pentru i  0,n-1 execută
Pseudo cod 4 a2[i]  a[n-1-i]
5 ■
6 *) aplicăm LCS
7 lung  LCS(a, n, a2, n)
8 *) tipărim subsecvenţa palindromică
9 TipăreşteLCS(a, n, a2, n, lung)
10 sf.procedură

Algoritmul CelMaiLungPalindrom are complexitatea Θ(n2), atât temporală cât şi


spaţială. O rezolvare completă a problemei în limbajul C# incluzând citirea și afișarea
datelor precum și generarea datelor de test este prezentată în continuare.
Ghid practic pentru analiza şi proiectarea algoritmilor. Aplicații în C# 101

class CelMaiLungPalindrom
{
static void Main(string[] args)
{
new CelMaiLungPalindrom();
}

public CelMaiLungPalindrom()
{
GenerateTests();
}

/// <summary>
/// Genereaza teste pentru problema palindromului
/// </summary>
private void GenerateTests()
{
int[] n = new int[] {
5, 10, 100, 300, 500, 700, 800, 900, 950, 999 };
for (int indexTest = 0; indexTest < n.Length; indexTest++)
{
int[] a = GenerateArray(n[indexTest]);
WriteToFile(a, "input-"+ (indexTest+1).ToString()+".txt");
int start = Environment.TickCount;
using (StreamWriter writer = new StreamWriter(
"output-" + (indexTest + 1).ToString() + ".txt"))
writer.WriteLine(Solve(a));
int end = Environment.TickCount;
Console.WriteLine("time = {0} ms", end - start);
}
}

/// <summary>
/// Genereaza un sir de numere alese la intamplare
/// </summary>
Random random = new Random();
private int[] GenerateArray(int n)
{
int[] a = new int[n];
for (int i = 0; i < n; i++)
a[i] = random.Next(100);
return a;
}

/// <summary>
/// Rezolva problema palindromului
102 Ghid practic pentru analiza şi proiectarea algoritmilor. Aplicații în C#

/// </summary>
private int Solve(int[] a)
{
int[] aReversed = new int[a.Length];
for (int i = 0; i < a.Length; i++)
aReversed[i] = a[a.Length - 1 - i];
return LengthOfLongestPalindrome(a, aReversed);
}

/// <summary>
/// Problema LCS
/// </summary>
private int LengthOfLongestPalindrome(int[] a, int[] b)
{
int n = a.Length;
int[,] length = new int[n, n];

length[0, 0] = (a[0] == b[0]) ? 1 : 0;


for (int j = 1; j < n; j++)
length[0, j] = (a[0] == b[j]) ? 1 : length[0, j - 1];
for (int i = 1; i < n; i++)
length[i, 0] = (a[i] == b[0]) ? 1 : length[i - 1, 0];

for (int i = 1; i < n; i++)


for (int j = 1; j < n; j++)
length[i, j] = max(
length[i - 1, j],
length[i, j - 1],
length[i - 1, j - 1] + (int)((a[i]==b[j]) ? 1 : 0));
return length[n - 1, n - 1];
}

private int max(int a, int b, int c)


{
return Math.Max(a, Math.Max(b, c));
}

/// <summary>
/// Afiseaza solutia la consola
/// </summary>
private void WriteToConsole(int[] a)
{
for (int i = 0; i < a.Length; i++)
Console.Write("{0}, ", a[i]);
Console.WriteLine();
}
Ghid practic pentru analiza şi proiectarea algoritmilor. Aplicații în C# 103

/// <summary>
/// Afiseaza solutia intr-un fisier
/// </summary>
private void WriteToFile(int[] a, string fileName)
{
using (StreamWriter writer = new StreamWriter(fileName))
{
writer.WriteLine(a.Length);
for (int i = 0; i < a.Length; i++)
writer.Write("{0}{1}", a[i], i==a.Length-1 ? "" : " ");
}
}

/// <summary>
/// Citeste datele problemei dintr-un fisier
/// </summary>
private int[] ReadFromFile(string fileName)
{
int[] a = null;
using (StreamReader reader = new StreamReader(fileName))
{
int n = int.Parse(reader.ReadLine());
string[] values = reader.ReadLine().Trim().Split(' ');
a = new int[n];
for (int i = 0; i < n; i++)
a[i] = int.Parse(values[i]);
}
return a;
}
}

5.3 Problema excursiilor

Excursii
Un grup de prieteni povestesc excursiile la care au participat şi mai
ales oraşele pe care le-au vizitat. Fiecare dintre ei precizează în ordine
Problemă oraşele vizitate. În final, ei se hotărăsc să determine care este cel mai
mare număr de oraşe pe care toţi le-au vizat în aceeaşi ordine.
Fişierul de intrare conţine pe prima linie numărul T de teste. Fiecare
test conţine pe prima linie numărul n≤20 de prieteni iar fiecare
dintre cele n linii următoare conţine oraşele vizitate (în ordinea
vizitării lor) separate printr-un spaţiu (fiecare prieten a vizitat un
număr de maxim 100 de oraşe).
104 Ghid practic pentru analiza şi proiectarea algoritmilor. Aplicații în C#

Fişierul de ieşire va conţine câte o linie pentru fiecare test


reprezentând numărul maxim de oraşe care au fost vizitate în aceeaşi
ordine de către toţi prietenii.
input.txt output.txt
2 3
3 0
Paris Roma Milano Bucuresti Praga
Roma Amsterdam Milano Praga Sofia Budapesta
Londra Paris Roma Venetia Milano Barcelona Praga
2
Londra Amsterdam
Praga Budapesta
Explicaţie: pentru primul test numărul maxim de oraşe vizitate în
aceeaşi ordine este 3 (Roma, Milano, Praga); pentru al doilea test nici
un oraş nu a fost vizitat de cei 2 prieteni.

Prezentăm în continuare rezolvarea completă a problemei în limbajul C# incluzând


funcțiile de lucru cu fișiere precum și un generator de date de teste aleatoare.
Rezolvarea folosește algoritmul de determinare a subsecvenței comune crescătoare
de lungime maximă aplicată pe rând tuturor mulțimilor de orașe, lucrând de această
dată cu date de tip string.

using System;
using System.Collections.Generic;
using System.IO;
using System.Text;

namespace Excursii
{
class Program
{
private Random random = new Random();
static void Main(string[] args)
{
new Program();
}

public Program()
{
Solve();
}
private void Solve()
Ghid practic pentru analiza şi proiectarea algoritmilor. Aplicații în C# 105

{
StreamReader reader = null;
StreamWriter writer = null;
try
{
reader = new StreamReader("input.txt");
writer = new StreamWriter("output.txt", false);
int T = int.Parse(reader.ReadLine());
for (int indexTest = 0; indexTest < T; indexTest++)
{
int n = int.Parse(reader.ReadLine());
List<List<string>> cities =
new List<List<string>>();
for (int i = 0; i < n; i++)
cities.Add(new List<string>(
reader.ReadLine().Split(new char[] { ' ' })));
writer.WriteLine(Solve(n, cities));
}
}
catch (Exception exc) { Console.WriteLine(exc.ToString());}
finally
{
if (reader != null) reader.Close();
if (writer != null) writer.Close();
}
}
private int Solve(int n, List<List<string>> cities)
{
List<string> solution = Solve(cities[0], cities[1]);
for (int i = 2; i < n; i++)
solution = Solve(solution, cities[i]);
return solution.Count;
}

private List<string> Solve(List<string> a, List<string> b)


{
if (a.Count == 0 || b.Count == 0)
return new List<string>();
int[,] c = new int[a.Count, b.Count];

c[0,0] = a[0] == b[0] ? 1 : 0;


for (int i = 1; i < a.Count; i++)
c[i, 0] = a[i] == b[0] ? 1 : c[i - 1, 0];
for (int j = 1; j < b.Count; j++)
c[0, j] = a[0] == b[j] ? 1 : c[0, j - 1];
for(int i = 1; i < a.Count; i++)
106 Ghid practic pentru analiza şi proiectarea algoritmilor. Aplicații în C#

for (int j = 1; j < b.Count; j++)


c[i, j] = Math.Max(
c[i - 1, j],
Math.Max(
c[i, j - 1],
c[i - 1, j - 1] + (a[i] == b[j] ? 1 : 0)));

int ii = a.Count - 1;
int jj = b.Count - 1;
List<string> cities = new List<string>();
while (!(ii == 0 && jj == 0))
{
if (ii > 0 && jj > 0 && c[ii, jj]==c[ii - 1, jj - 1]+1)
{
cities.Add(a[ii]);
ii--;
jj--;
}
else
if (ii > 0 && c[ii, jj] == c[ii - 1, jj]) ii--;
else
if (ii > 0 && jj == 0 &&
c[ii, jj] == c[ii - 1, jj] + 1) {
cities.Add(a[ii]);
ii--;
}
else
if (jj > 0 && c[ii, jj] == c[ii, jj - 1])
jj--;
else
if (ii == 0 && jj > 0 &&
c[ii, jj] == c[ii, jj - 1] + 1)
{
cities.Add(a[ii]);
jj--;
}
}
if (a[0] == b[0]) cities.Add(a[0]);
cities.Reverse();
return cities;
}

private void GenerateTests()


{
StreamWriter writer = null;
try
{
Ghid practic pentru analiza şi proiectarea algoritmilor. Aplicații în C# 107

writer = new StreamWriter("input.txt", false);


int T = 10;
writer.WriteLine(T);
int[] n = new int[] {2, 2, 2, 2, 2, 5, 5, 10, 20, 20};
List<string> cities = GenerateCities();
for (int indexTest = 0; indexTest < T; indexTest++)
{
writer.WriteLine(n[indexTest]);
for (int i = 0; i < n[indexTest]; i++)
{
int m = cities.Count / 2 +
random.Next(cities.Count / 2);
bool[] visited = new bool[cities.Count];
for (int index=0; index < cities.Count;index++)
visited[index] = false;
for (int index = 0; index < m; index++)
{
int j = -1;
do
{
j = random.Next(cities.Count);
} while (visited[j]);
visited[j] = true;
writer.Write("{0}{1}", cities[j],
index == m - 1 ? "" : " ");
}
writer.WriteLine();
}
}
}
catch { }
finally
{
if (writer != null) writer.Close();
}
}

private List<string> GenerateCities()


{
List<string> cities = new List<string>();
for (int i = 0; i < 100; i++)
cities.Add(GenerateCity());
return cities;
}
108 Ghid practic pentru analiza şi proiectarea algoritmilor. Aplicații în C#

private string GenerateCity()


{
string city = "";
int n = random.Next(5, 10);
for (int i = 0; i < n; i++)
city += (char)('A' + random.Next(26));
return city;
}
}
}

5.4 Probleme propuse

Subsecvența comună maximală


Implementaţi problema LCS pentru două şiruri de numere întregi.
Datele vor fi citite dintr-un fişier ce conţine pe prima linie numărul de
Problema
elemente n iar pe a doua linie elementele mulţimii a separate printr-
#1
un spaţiu. Următoarele două linii vor codifica similar şirul b. Fişierul de
ieşire va conţine pe prima linie lungimea subsecvenţei maxime iar pe a
doua elementele subsecvenţei separate prin spaţiu.
Intrare Ieşire
11 4
7 6 5 2 8 2 8 1 4 7 10 6287
7
6921897
Pentru date de intrare care permit mai multe soluţii de lungime
maximă, afişaţi două subsecvenţe distincte.
Care este complexitatea algoritmului de afișare a acestora?
Cum puteţi generaliza algoritmul pentru aflarea subsecvenţei comune
de lungime maximă pentru r şiruri de numere întregi?
Care este complexitatea algoritmului obţinut?

Verificarea vocabularului
Fie un dicţionar alcătuit dintr-un număr de n cuvinte şi fie m cuvinte
introduse de către un utilizator într-un editor text. Realizaţi operaţia de
Problema verificare a vocabularului, corectând cuvintele introduse de utilizator
#2 pe baza celor din dicţionar.
Fişierul de intrare conţine pe prima linie numărul n de cuvinte din
Ghid practic pentru analiza şi proiectarea algoritmilor. Aplicații în C# 109

dicţionar. Următoarele n linii vor conţine fiecare cuvânt din dicţionar.


Nu există spaţii sau caractere speciale în interiorul cuvintelor ci doar
litere din intervalul ’a’..’z’. Următoarea linie va conţine numărul m de
cuvinte introduse în editorul text, fiecare cuvânt aflându-se pe una
dintre cele m linii ce urmează în fişier. Fişierul de ieşire va conţine
cuvintele corectate conform dicţionarului.
Intrare Ieşire
4 univers
mare banca
univers banca
banca
stilou
3
univesr
banca
bnca

Turnurile de cuburi
Fie două turnuri construite din n respectiv m cuburi de culori c1i și c2j.
Dintr-un turn putem elimina orice cub de pe orice poziţie, lungimea
Problema turnului diminuându-se cu 1. Determinaţi numărul minim de cuburi ce
#3 trebuie eliminate astfel încât să obţinem două turnuri identice de
aceeaşi înălţime cu cuburi de pe acelaşi nivel având aceiaşi culoare.
Fişierul de intrare conţine numărul de cuburi n din primul turn
respectiv m din al doilea. Următoarea linie conţine descrierea primului
turn: n valori separate prin spaţiu reprezentând culorile cuburilor ce
alcătuiesc turnul. A treia linie din fişier va conţine descrierea celui de-al
doilea turn. Fişierul de ieşire conţine pe prima linie numărul minim de
cuburi care trebuie eliminate din ambele turnuri. Următoarea linie
conţine indicii cuburilor ce vor fi eliminate din primul turn iar a treia
linie indicii cuburilor eliminate din cel de-al doilea turn.
Intrare Ieşire
45 3
200 100 130 100 1
24 200 130 177 100 03
110 Ghid practic pentru analiza şi proiectarea algoritmilor. Aplicații în C#

Excursii (2)
Un grup de prieteni povestesc excursiile în care au participat şi mai ales
oraşele pe care le-au vizitat. Fiecare precizează în ordine oraşele
Problema vizitate. În final, ei vor să afle care este cel mai mare număr de oraşe
#4 pe care fiecare le-a vizat astfel încât numele orașelor să fie în ordine
alfabetică. Fişierul de intrare conţine pe prima linie numărul T de
prieteni (sau de teste). Fiecare test conţine pe două linii oraşele
vizitate. Fişierul de ieşire conţine câte o linie pe test reprezentând
numărul maxim de oraşe vizitate în aceeaşi ordine de toţi prietenii.
Intrare Ieșire
3 2
5 4
Paris Roma Milano Bucuresti Praga 4
6
Roma Amsterdam Milano Praga Sofia
Budapesta
7
Londra Paris Roma Venetia Milano
Barcelona Praga

S-ar putea să vă placă și