Описание Генератор случайных карт известной игры Heroes of Might and Magic III создает острова, на которых изначально будут расположены герои. При такой генерации острова получаются различными по величине. Назовем коэффициентом несправедливости отношение площади наибольшего острова к площади наименьшего Карта задается прямоугольником N×M, в каждой клетке которого записана цифра "0" - вода или цифра "1" - земля. Островом считается максимальное связное множество клеток, содержащих единички, т.е. такое множество клеток A, что:из любой клетки A можно пройти до любой другой клетки A, переходя лишь через клетки A и их стороны при добавлении к A любой другой клетки, содержащей 1, предыдущее условие нарушается
Задание Определите коэффициент несправедливости Входные данные В первой строке входного файла содержатся числа N и M - размеры карты (1≤N,M≤1000). Далее записана сама карта - M строк по N чисел ("0" или "1") в каждой. Числа внутри строки разделяются пробелом Выходные данные В выходной файл вывести коэффициент несправедливости с 5 знаками после десятичной точки. Если на карте нет ни одного острова, вывести число "0" Например: ISLANDS.IN 7 6 1 1 0 0 0 0 0 0 1 0 1 0 0 0 1 1 0 1 1 0 0 1 0 0 0 1 0 0 0 0 0 1 1 1 0 1 1 1 0 0 1 0 ISLANDS.OUT 2.66667
Идеи Операции над матрицей Комментарии На первый взгляд задача кажется совершенно стандартной, однако указанные в условии ограничения не позволяют решить ее привычным способом. Можно, конечно, попытаться разместить матрицу 1000×1000 в динамической памяти побитово и написать нерекурсивный вариант процедуры ее просмотра, чтобы не происходило переполнения стека. Этот способ приведет к успеху, однако мы рассмотрим более красивое решение данной задачи Будем просматривать матрицу по строчкам сверху вниз. В каждый момент времени храним в памяти только текущую и предыдущую строчки матрицы. Также будем помнить максимальный и минимальный размеры островов, которые мы уже полностью просмотрели, текущие размеры островов, которые мы видим в данный момент, а для каждой единички в строках, которые мы просматриваем, - к какому острову она относится. Единичка (или группа единичек, стоящих подряд) в текущей строке может быть: Началом нового острова, если сверху (т.е. на той же позиции в предыдущей строке) от всех единичек стоят ноли. Например, 1 0 0 0 0 0 1 1 0 1 Продолжением какого-то острова, начавшегося в предыдущей строке или раньше, если хотя бы над одной из единичек группы стоит единичка. Например, 0 1 0 0 0 1 1 0 Одна группа единичек может служить продолжением сразу нескольких островов. Тогда эти острова объединяются (т.е. далее рассматриваются как один остров), а их текущие площади складываются. Например, 0 1 0 1 0 1 1 1 1 1
В этом случае при просмотре первой строки две единички будут рассматриваться как самостоятельные острова, а при рассмотрении второй строки «объединятся» в один остров. Однако, в следующем случае: 1 1 1 1 1 0 0 1 1 1 1 1
при рассмотрении третьей строки не нужно производить объединение островов, потому что эти единички принадлежат одному и тому же острову (т.к. при переходе от первой строки ко второй они являлись соседями единичек, принадлежащих одному острову)
Решение {$A+,B-,D+,E+,F-,G-,I+,L+,N-,O-,P-,Q+,R+,S+,T-,V+,X+} {$M 65384,0,655360} {$A+,B-,D-,E-,F-,G-,I-,L-,N-,O-,P-,Q-,R-,S-,T-,V-,X-} {$N+} program islands; Const InputFile='islands.in'; OutputFile='islands.out'; MaxN=1000; MaxM=1000; MaxSp=15000; epsout=6; Dx: Array[1..4] Of Integer=( 0, 0,-1, 1); Dy: Array[1..4] Of Integer=(-1, 1, 0, 0); Type Sset=Set Of 0..7; TSmall=Array[0..125] Of SSet; Var A: Array[1..MaxN] Of ^TSmall; N, M: Integer; Max, Min: LongInt; rs: Extended; Procedure AddA(i, j: Integer); Begin Include(A[i]^[j shr 3], j And 7); End; Procedure DeleteA(i, j: Integer); Begin Exclude(A[i]^[j shr 3], j And 7); End; Function ExisA(i, j: Integer): Boolean; Begin ExisA:=(j And 7) In A[i]^[j shr 3]; End; Procedure Init; Var i, j, k: Integer; Begin Assign(Input, InputFile); Reset(Input); Read(M, N); For i:=1 To N Do Begin New(A[i]); FillChar(A[i]^, SizeOf(A[i]^), 0); For j:=1 To M Do Begin Read(k); If k=1 Then AddA(i, j); End; End; Close(Input); Max:=0; Min:=MaxLongInt; End; Var Ox, Oy: Array[1..MaxSp] Of Integer; Procedure Delet(Const k, p: Integer; Var rs: LongInt); Var nx, ny, dwnf, i, upf, down, up: LongInt; Begin dwnf:=1; upf:=1; down:=1; up:=1; Ox[1]:=k; Oy[1]:=p; DeleteA(k, p); Repeat For i:=1 To 4 Do Begin nx:=Ox[dwnf]+Dx[i]; ny:=Oy[dwnf]+Dy[i]; If (nx>0) And (ny>0) And (nx<=N) And (ny<=M) And ExisA(nx, ny) Then Begin DeleteA(nx, ny); Inc(up); upf:=upf Mod MaxSp + 1; Ox[upf]:=nx; Oy[upf]:=ny; End; End; Inc(down); dwnf:=dwnf Mod MaxSp + 1; Until down>up; rs:=up; End; Procedure Solve; Var i, j: Integer; rs: LongInt; Begin For i:=1 To N Do For j:=1 To M Do If ExisA(i, j) Then Begin Delet(i, j, rs); If rsThen Min:=rs; If rs>Max Then Max:=rs; End; End; Procedure Done; Begin Assign(Output, OutputFile); Rewrite(Output); If Max=0 Then WriteLn(0) Else Begin rs:=Max/Min; WriteLn(rs:0:epsout); End; Close(Output); End; BEGIN Init; Solve; Done; END.
|