Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2002.12.12;
Скачать: CL | DM;

Вниз

Очередная несложная задачка для разминки;)   Найти похожие ветки 

 
MBo ©   (2002-11-21 10:03) [0]

Найти количество S пpавильных скобочных последовательностей длины 2N (1<=N<=30)
Пpимеp: 2N=6:
((())), (()()), ()()(), (())(), ()(())
S= 5

Задача, естественно, не в нахождении формулы, а в составлении алгоритма программы

(взято с fido.ru.algoritms)


 
McSimm ©   (2002-11-21 10:43) [1]

Очевидное решение - рекурсивно.
Может есть неочевидное и более простое?


 
MBo ©   (2002-11-21 10:45) [2]

я тоже рекурсивно делал, без рекурсии пока не пробовал


 
Igorek ©   (2002-11-21 10:49) [3]


> MBo © (21.11.02 10:03)

На выходные надо задавать, когда время есть. А то работа еще...
:-)


 
Igorek ©   (2002-11-21 10:52) [4]


> McSimm © (21.11.02 10:43)
> Очевидное решение - рекурсивно.
> Может есть неочевидное и более простое?

В любом случае алгоритм аналогичный рекурсивному. Можно через стек. Также можно дать рекурентную формулу.


 
Alx2 ©   (2002-11-21 11:53) [5]

Хм... :))


function sCount(stop, sum: integer): Integer;
begin
if stop = 0 then
Result := cardinal(sum=0)
else
begin
Result := sCount(stop - 1, sum + 1);
if sum > 0 then
inc(Result, sCount(stop - 1, sum - 1));
end;
end;
begin
ShowMessage(IntToStr(sCount(6 {длина последовательности}, 0)));
end;


 
Оливейра ©   (2002-11-21 12:56) [6]

На CBOSS.ru такую х... на тестовом задании предлагают, только на голых сях. В общем-то нерекурсивно даже проще - ищется первая открывающая скобка, копируется указатель на нее, во вложенном втором цикле ищется, начиная с этого указателя, закрывающая и подсчитывается количество открывающих и закрывающих скобок, найденных попутно. Если найдена закрывающая и число найденных открывающих равно числу закрывающих (0-0, 1-1 и т.п.) значит, найдена парная.


 
Alx2 ©   (2002-11-21 13:44) [7]

>Оливейра © (21.11.02 12:56)
"Найти количество S пpавильных скобочных последовательностей длины 2N (1<=N<=30)
Пpимеp: 2N=6:
((())), (()()), ()()(), (())(), ()(())
S= 5"


 
MBo ©   (2002-11-21 13:45) [8]

>Alx2
отлично

>Оливейра
Это другая задача - в твоей нужно проверить сбалансированность скобок в выражении, решается прямым однопроходным прогоном, а здесь нужно кратчайшим способом перечислить все правильные комбинации


 
down   (2002-11-21 13:50) [9]

2Alx2
Можно пояснить, как работает?


 
MBo ©   (2002-11-21 13:57) [10]

мой вариант

procedure TForm1.Button1Click(Sender: TObject);
var
nmax, nhalf, NVar: integer;
s: string;

procedure AddSkobka(n, nl, right: integer);
begin
s[n * 2] := Chr(Ord("(") + right);
if right = 0 then
inc(nl);
if n = nmax then
begin
Memo1.Lines.Add(s);
inc(NVar);
Exit;
end;
if 2 * nl > n then
//если левых больше, чем правых, можно добавить правую
AddSkobka(n + 1, nl, 1);
if nl < nhalf then
//если левых половина общего количества, перестаем их добавлять
AddSkobka(n + 1, nl, 0);
end;

begin
nhalf := 4;
nmax := nhalf *2;
nvar := 0;
s := StringOfChar(" ", 2 * nmax);
AddSkobka(1, 0, 0);
Memo1.Lines.Add(IntToStr(NVar));
end;


 
MBo ©   (2002-11-21 14:03) [11]

решение задачи Оливейры
функция считает макс. глубину вложения, выдавая 255 для случая дисбаланса

function skobki(st:string):byte;
var i,j,max:byte;
begin
max:=0;
j:=0;
for i:=1 to length(st) do begin
if st[i]="(" then inc(j);
if st[i]=")" then dec(j);
if max<j then max:=j;
end;
if j<>0 then
max:=255;
Result:=max;
end;


 
MBo ©   (2002-11-21 15:08) [12]

пардон, последний постинг неправильный. Так вернее:

procedure TForm1.Button5Click(Sender: TObject);

function VernyeSkobki(st:string):Boolean;
var i,j:byte;
begin
Result:=False;
j:=0;
for i:=1 to length(st) do begin
if st[i]="(" then inc(j);
if st[i]=")" then
if j>0 then
dec(j)
else
Exit;
end;
Result:=j=0;
end;

begin
If VernyeSkobki("(()())") then
ShowMessage("OK")
else
ShowMessage("Fignya");
end;


 
Alx2 ©   (2002-11-21 15:42) [13]

>MBo © (21.11.02 13:57)

Вот с выдачей результатов:


function RunProcess(Dimension: Integer): integer;
var S: string;
function sCountWithResult(stop, sum: integer): Integer;
begin
if stop = 0 then
if sum = 0 then
begin
Result := 1;
Memo1.Lines.Add(S)
end
else Result := 0
else
begin
S[Stop] := ")";
Result := sCountWithResult(stop - 1, sum + 1);
if sum > 0 then
begin
S[Stop] := "(";
inc(Result, sCountWithResult(stop - 1, sum - 1));
end;
end;
end;

begin
SetLength(S, Dimension);
Result := sCountWithResult(Dimension, 0);
end;

begin
RunProcess(6);
end;


 
MBo ©   (2002-11-21 15:46) [14]

>Alx2
Угу. Но главное- алгоритм, маленький и симпатичный ;)


 
Alx2 ©   (2002-11-21 15:51) [15]

>down (21.11.02 13:50)
>Можно пояснить, как работает?

Можно, конечно.
Если представить заполняемую скобками последовательность как последовательность элементов "-1" и "1", где "-1" означает закрывающую скобку, а "1" - открывающую скобку, то для того, чтобы соблюсти правильность парности скобок, достаточно потребовать, чтобы сумма элементов по мере заполнения массива никогда не была меньше нуля. Отсюда следует условие
if sum > 0 then
.....

Остальное - простая рекурсия :)


 
down   (2002-11-21 16:23) [16]

Понятно, спасибо! Красиво, черт побери!


 
Alx2 ©   (2002-11-21 16:27) [17]

>down (21.11.02 16:23)

:)


 
Igorek ©   (2002-11-22 10:30) [18]


> Alx2 © (21.11.02 16:27)

А еще полный перебор можно представить в виде бинарного дерева, где каждый узел имеет суму предыдущих и свое число (1 или -1). В данном случае реализован метод ветвей и границ - поиск обрывается при отрицательной сумме.
Но вот нерекурентную простую формулу не могу найти. :-(
Еще подумаю.



Страницы: 1 вся ветка

Текущий архив: 2002.12.12;
Скачать: CL | DM;

Наверх




Память: 0.51 MB
Время: 0.018 c
1-36136
Berser
2002-12-01 01:06
2002.12.12
Класные инструменты KDTele Tools v.3.0.31


1-36223
Seldon
2002-12-01 17:35
2002.12.12
Pascal


14-36396
Rand
2002-11-21 18:29
2002.12.12
Экспресс-анкета


1-36111
KMI
2002-12-03 11:19
2002.12.12
Как создать текстовый файл в DOS-кодировке?


1-36273
DimonA
2002-12-02 14:18
2002.12.12
QReport