Program Tiles; Const MaxSize=500; Var f: Text; tile: Array [1..MaxSize, 1..MaxSize] of Char; // поле - цвета клеток mark: Array [1..MaxSize, 1..MaxSize] of Boolean; // обработана ли клетка N, M: Word; //высота и ширина поля i0, j0, i, j, stepi, stepj, di, dj: LongInt; ch: Char; result: Array ['a'..'z'] of Boolean; //храним цвета, по которым есть бесконечный путь delta: Array [1..MaxSize, 1..MaxSize] of Record i, j: LongInt; End; queue: Array [1..MaxSize*MaxSize] of Record // очередь клеток, ожидающих обработки в поиске в ширину i, j: LongInt; End; qr, qw: LongInt; // индексы в очереди поиска в ширину: qr - голова очереди (позиция чтения) // qw - хвост очереди (позиция добавления клетки) Begin {Считываение и инициализация данных} Assign(f, 'tiles.in'); Reset(f); Readln(f, N); M:= N; For i:= 1 To N Do Begin For j:= 1 To M Do Begin Read(f, tile[i,j]); mark[i,j]:= False; End; Readln(f); End; Close(f); For ch:= 'a' To 'z' Do Begin result[ch]:= False; End; {Поиск в ширину. Для каждой посещаемой клетки храним delta - } {величину смещения от начальной клетки в поиске в ширину до неё} {Считаем, что левый край поля соединён с правым, а верхний - с нижним} For i0:= 1 To N Do Begin For j0:= 1 To M Do Begin If mark[i0,j0] Then Continue; ch:= tile[i0, j0]; delta[i0,j0].i:= 0; delta[i0,j0].j:= 0; queue[1].i:= i0; queue[1].j:= j0; qr:= 1; qw:= 2; While qrN Then i:= 1; j:= queue[qr].j + stepj; If j<1 Then j:= M; If j>M Then j:= 1; If tile[i,j]=ch Then Begin If not mark[i,j] Then Begin mark[i,j]:= True; delta[i,j].i:= delta[queue[qr].i, queue[qr].j].i + stepi;; delta[i,j].j:= delta[queue[qr].i, queue[qr].j].j + stepj;; queue[qw].i:= i; queue[qw].j:= j; Inc(qw); End; End; End; End; Inc(qr); End; End; End; {Проверяем все пары соседних клеток - как смежные по вертикали, так и по горизонтали.} {Как и выше, считаем, что клетки на левом краю поля соседствуют с клетками на правом } {краю, а клетки из верхнего ряда смежны с клетками из нижнего. } For i0:= 1 To N Do Begin For j0:= 1 To M Do Begin If result[tile[i0,j0]] Then Continue; For stepi:= 0 To 1 Do Begin stepj:= 1 - stepi; i:= i0 + stepi; If i<1 Then i:= N; If i>N Then i:= 1; j:= j0 + stepj; If j<1 Then j:= M; If j>M Then j:= 1; If tile[i0,j0]<>tile[i,j] Then Continue; di:= delta[i,j].i - delta[i0,j0].i - stepi; dj:= delta[i,j].j - delta[i0,j0].j - stepj; If (di<>0) or (dj<>0) Then Begin result[tile[i,j]]:= True; { Если две соседних одноцветных клетки достигнуты в процессе } { поиска в ширину c "разных" сторон, то: идём от одной из них } { до начальной клетки в поиске в ширину, потом от начальной до } { второй клетки, и потом одним шагом переходим из второй } { клетки в первую - получаем ""круговой" маршрут } End; End; End; End; Assign(f, 'tiles.out'); Rewrite(f); For ch:= 'a' To 'z' Do Begin If result[ch] Then Begin Write (f, ch); End; End; Writeln(f); Close(f); End.