Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Вывод всех перестановок k элементов из множества N имеющихся [D7]


Страницы:   1 2 3

ННН ©   (2012-10-28 23:00:00) 

Всем привет нужен алгоритм (любой на словах или кодом) выводящий все перестановки k элементов (не повторяющихся) из множества N имеющихся.
т.е. Пусть N=6, {1,2,3,4,5,6}, k=4
1 2 3 4
1 2 3 5
1 2 3 6
1 2 4 5
1 2 4 6
1 2 5 6
1 3 4 5
и т.д.


Sha   (2012-11-09 21:52:00) [1]

вот тут еще немного быстрее:

http://guildalfa.ru/alsha/node/26


Очень злой   (2012-11-06 09:09:00) [2]

М-да, а если принимать во внимание время, то все равно алгоритм Sha намного (причем очень)  быстрее получается...


Очень злой   (2012-11-06 01:48:00) [3]


>  один из способов перечисления размещений состоит в использовании
> перестановок и сочетаний, а именно во всевозможных перестановках
> элементов каждого сочетания


Если так то:

var
 n,s:string;
...

//ищем перестановки
procedure recurse2(s:string;pos:integer);
var
 c:char;
 i:integer;
begin
if pos>=length(s) then Form1.Memo1.Lines.Add(s)
 else for i:=pos to length(s) do
   begin
      c:=s[pos];
      s[pos]:=s[i];
      s[i]:=c;
      recurse2(s,pos+1);
   end;
end;

// Ищем сочетания
procedure recurs(pos,start,last,endd:integer);
var
 i:integer;
begin
 if last>endd then recurse2(s,1)
   else for i:=start to last do
        begin
          s[pos]:=n[i];
          recurs(pos+1,i+1,last+1,endd);
        end;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
 n:=Edit1.text;
 setlength(s,SpinEdit1.Value);
//  Memo1.Lines.Clear;
//  Memo1.Lines.BeginUpdate;
 recurs(1,1,length(Edit1.Text)-SpinEdit1.Value+1,Length(Edit1.text));
//  Memo1.Lines.EndUpdate;
end;


Насчет скорости не замерял... да и намутил я тут, много чего неоптимально , можно улучшить,
например length(s) вычислять не нужно , так как оно всегда равно spinedit1.value, ну и еще есть чего оптимизировать


Очень злой   (2012-11-06 01:21:00) [4]

Попробовал запустить код Sha, и понял что я неправильно понял условие...
Сейчас еще подумаю


Очень злой   (2012-11-06 00:55:00) [5]

Вроде так... Правда порядок определяется порядком следования символов в Edit1

например:
Edit1.text='abcd6r'   K=4

abcd
abc6
abcr
abd6
abdr
ab6r
acd6
acdr
ac6r
ad6r
bcd6
bcdr
bc6r
bd6r
cd6r


Очень злой   (2012-11-06 00:46:00) [6]

Представил себе эту ветку в виде пятничной задачки. :)
Посему и захотелось ее решить.

По первому посту не совсем понял задачу, в приведенных кодах не разбирался, ссылки не читал, но судя по примерам того что должны мы получать,  задачу я понял так: Нужно получить все (не помню что такое перестановка, скажу по другому) комбинации K неповторяющихся элементов из множества N-элементов, причем идущих всегда в одном порядке (например алфавитном).

У меня получилось такое:

В Edit1 вбиваем последовательность нужных элементов
соответственно его длина это будет N

В spinedit1 вбиваем значение K

var
 n,s:string;
...
procedure recurs(pos,start,last,endd:integer);
var
 i:integer;
begin
 if last>endd then Form1.Memo1.Lines.add(s)
   else for i:=start to last do
        begin
          s[pos]:=n[i];
          recurs(pos+1,i+1,last+1,endd);
        end;
end;
...
procedure TForm1.Button1Click(Sender: TObject);
begin
 n:=Edit1.text;
 setlength(s,SpinEdit1.Value);
 recurs(1,1,length(Edit1.Text)-SpinEdit1.Value+1,Length(Edit1.text));
end;


и получаем все в memo1


ННН   (2012-11-05 14:51:00) [7]

Вот эту строчку надо изменить, s2[i]:=Edit1.Text[1]
for i:=1 to n do s2[i]:=AnsiChar(Ord('a')-1+i);
как то так) ладно в конце недели сделаю как курсач сдам


Sha   (2012-11-05 10:50:00) [8]

> ННН   (05.11.12 10:16) [36]

Совсем небольшое изменение. Пусть это будет домашнее задание.


ННН   (2012-11-05 10:16:00) [9]

да работает вроде как сильно шустро)) а что если его доработать, чтобы он работал со строкой, т.е. в одно поле вводишь строку 234 а в другое  К


Sha   (2012-11-04 01:54:00) [10]

Ускорил код [34] еще примерно на 20% для больших n, k:
(проц=E6850, n=13, k=12, t=42 sес)


procedure GenerateArrangements3(n, k: integer);
var
 i, len: integer;
 s1, s2: string[255];
 ch: AnsiChar;
begin;
 if (k<=0) or (n<k) or (n>255) then exit;
 SetLength(s1,k);
 SetLength(s2,n);
 for i:=1 to n do s2[i]:=AnsiChar(Ord('a')-1+i);
 i:=n;
 len:=0;
 while true do begin;
   s1[len+1]:=s2[i];
   inc(len);
   s2[i]:=s2[len];            //заменить на сдвиг, если нужен алфавитный порядок
   s2[len]:=AnsiChar(i);
   i:=n;
   if len=k then begin;
     //Form1.Memo1.Lines.Add(s1);
     while true do begin;
       i:=Ord(s2[len]);
       s2[len]:=s2[i];        //заменить на сдвиг, если нужен алфавитный порядок
       s2[i]:=s1[len];
       dec(len);
       dec(i);
       if i>len then break
       else if i>0 then continue
       else exit;
       end;
     end;
   end;
 end;


Sha   (2012-11-03 12:54:00) [11]

В коде ниже используется тот же самый наивный подход к перебору размещений, что и в алгоритме gorfil.

Отличия:
1) нет рекурсии,
2) вместо сцепления строк работаем с блоком символов переменной длины внутри строки,
3) в качестве стека используется часть строки, не занятая этим блоком,
4) неалфавитный порядок генерации, т.к. вместо сдвига блока символов
используется перемещение крайнего символа на свободное место.

В результате получена совсем не плохая скорость: 11! перестановок за ~0.5 сек.
Алгоритм можно еще немного ускорить, но не думаю, что больше чем на 10%


procedure GenerateArrangements2(n, k: integer);
var
 i, len1, len2: integer;
 s1, s2: string[255];
begin;
 if (k<=0) or (n<k) then exit;
 SetLength(s1,k);
 SetLength(s2,n);
 for i:=1 to n do s2[i]:=AnsiChar(Ord('a')-1+i);
 i:=1;
 len1:=0;
 len2:=n;
 while true do begin;
   s1[len1+1]:=s2[i];
   s2[i]:=s2[len2];           //заменить на сдвиг, если нужен алфавитный порядок
   s2[len2]:=AnsiChar(i);
   inc(len1);
   dec(len2);
   i:=1;
   if len1=k then begin;
     //Form1.Memo1.Lines.Add(s1);
     repeat;
       if len1=0 then exit;
       i:=Ord(s2[len2+1]);
       s2[len2+1]:=s2[i];     //заменить на сдвиг, если нужен алфавитный порядок
       s2[i]:=s1[len1];
       inc(len2);
       inc(i);
       dec(len1);
       until i<=len2;
     end;
   end;
 end;

procedure TForm1.Button5Click(Sender: TObject);
var
 t: cardinal;
begin;
 t:=GetTickCount;
 GenerateArrangements2(11, 11);
 t:=GetTickCount-t;
 Memo1.Lines.Add(IntToStr(t)+' msec');
 end;


Германн   (2012-11-03 03:25:00) [12]


>  ННН   (03.11.12 00:08) [31]
>
> Sha ты прогаешь на с++?
>

Си и Си++  тут многие знают. Особенно Си. Есть "специальные" вопросы по Си++? Так задавай их.
А "прогают" только некоторые вроде тебя.


Sha   (2012-11-03 00:31:00) [13]

> там gorfil

идея алгоритма gorfil очень хороша,
после оптимизации вполне может оказаться быстрее, чем [29]

> прогаешь

тут общаются


ННН   (2012-11-03 00:08:00) [14]

Sha ты прогаешь на с++?


ННН   (2012-11-03 00:08:00) [15]

Sha))) Спасибо за участие! даже лучше сказать за потраченное время на меня. Зайди на
"Вероятно, ты о варианте (TStringList,Sorted=true,Duplicates=dupIgnore),
который тебе предложили на другом форуме." там gorfil  тоже очень хорошо поработал))


Sha   (2012-10-31 20:56:00) [16]

Теперь решение, правда довольно сырое,
но при желании его можно оптимизировать и получить вполне приличное.
В духе этого кода используемые цифры начинаются с 0, а не с 1.
Если требуется работать с k>9, надо переписать процедуру ShowArrangement  ))


type
 TPermutation= array of integer;
 TArrangement= array of integer;
 TCombinations= array of TArrangement;

function GenerateCombinations(n, k: integer): TCombinations;
var
 i, j, start, delta: integer;
begin;
 if (k<=0) or (n<k) then exit;
 i:=1; for j:=0 to k-1 do i:=i * (n-j) div (j+1);
 SetLength(Result, i, k);
 i:=0; for j:=0 to k-1 do Result[i,j]:=j;
 start:=k-1;
 if k<n then while true do begin; //если существует более одного сочетания крутим цикл
   if Result[i,k-1]<n-1
   then start:=k-1
   else begin;
     dec(start); if start<0 then break;
     end;
   inc(i);
   delta:=Result[i-1,start]-start+1;
   for j:=k-1 downto start do Result[i,j]:=j+delta;
   for j:=start-1 downto 0 do Result[i,j]:=Result[i-1,j];
   end;
 end;

procedure ShowArrangement(const Arrangement: TArrangement);
var
 j, val: integer;
begin;
 if Length(Arrangement)>9 then exit;
 val:=1;
 for j:=0 to Length(Arrangement)-1 do val:=val*10+Arrangement[j];
 Form1.Memo1.Lines.Add(Copy(IntToStr(val),2,255));
 end;

procedure ShowArrangements(const Permutation: TPermutation; const Combinations: TCombinations);
var
 Arrangement: TArrangement;
 i, j: integer;
begin;
 SetLength(Arrangement,Length(Permutation));
 for i:=0 to Length(Combinations)-1 do begin;
   for j:=0 to Length(Arrangement)-1 do Arrangement[j]:=Combinations[i,Permutation[j]];
   ShowArrangement(Arrangement);
   end;
 end;

procedure GenerateArrangements(n, k: integer);
var
 Combinations: TCombinations;
 Permutation: TPermutation;
 ExchangeIndex: array of integer;
 i, j, level, temp: integer;
begin;
 if (k<=0) or (n<k) then exit;
 Combinations:=GenerateCombinations(n, k);
 SetLength(Permutation,k);
 SetLength(ExchangeIndex,k);
 for i:=0 to k-1 do begin;
   Permutation[i]:=i;
   ExchangeIndex[i]:=i;
   end;
 ShowArrangements(Permutation, Combinations); //показываем сочетания для тождественной перестановки
 level:=k-2;
 //генерируем перестановки
 while true do begin;
   i:=ExchangeIndex[level]+1; //позиция символа, который поставим на место level
   if i<k then begin;         //допустимая? т.е. из диапазона level+1..k-1?
     ExchangeIndex[level]:=i; //сохранили новое значение, не меняем символы Permutation[0..level]
     i:=level+1; j:=k-1;
     repeat;
       //инвертируем порядок символов Permutation[level+1..k-1]
       temp:=Permutation[j]; Permutation[j]:=Permutation[i]; Permutation[i]:=temp;
       inc(i); dec(j);
       until i>=j;
     //обмен Permutation[level] и Permutation[ExchangeIndex[level]]
     i:=ExchangeIndex[level];
     temp:=Permutation[i]; Permutation[i]:=Permutation[level]; Permutation[level]:=temp;
     level:=k-2;
     ShowArrangements(Permutation, Combinations); //сочетания для очередной перестановки
     end
   else begin;
     ExchangeIndex[level]:=level;
     dec(level);
     if level<0 then break;
     end;
   end;
 end;

procedure TForm1.Button1Click(Sender: TObject);
begin;
 GenerateArrangements(6, 4);
 end;


Sha   (2012-10-31 20:41:00) [17]

Сначала приведу нечто, которое ничуть не хуже того, что тебе дали.
Решением это назвать нельзя, т.к. оно перебирает слишком много лишнего, прежде чем найдет нужное:


procedure TForm1.Button3Click(Sender: TObject);
const
 maxcipher= 9;
 power: array[0..maxcipher-1] of integer= (1, 2, 4, 8, 16, 32, 64, 128, 256);
var
 i, j, k, n, max, num, cip, tmp, used, count: integer;
 s: string[maxcipher];
begin;
 n:=6; k:=4;
//------------------
 count:=0;
 if (1<=k) and (k<=n) and (n<=maxcipher) then begin;
   SetLength(s,k);
   max:=1;
   for i:=1 to k do max:=max * n;
   for i:=0 to max-1 do begin;
     used:=0;
     num:=i;
     j:=k;
     repeat;
       tmp:=num div n;
       cip:=num - tmp * n;
       if used and power[cip]<>0 then break;
       used:=used or power[cip];
       s[j]:=AnsiChar(cip+Ord('1'));
       num:=tmp;
       dec(j);
       until j=0;
     if j=0 then begin;
       inc(count);
       Memo1.Lines.Add(s);
       end;
     end;
   end;
 Memo1.Lines.Add('total='+IntToStr(count));
 end;


ННН   (2012-10-31 16:00:00) [18]

))


Sha   (2012-10-31 15:35:00) [19]


> ННН   (31.10.12 15:26) [25]


как дома будет время, напишу что-нибудь, как-то так )


ННН   (2012-10-31 15:26:00) [20]

учитывая то что я не прогал 7 лет, и понятия не имел  без практики  как работают рекурсивные функции + мозг был вынесен реализацией проекта после длительного отдыха и он был готов за исключением данного алгоритма, то я бы назвал это помощью, а если учитывать что я окончательно разобрался и прорешал весь алгоритм на листочке, то можно назвать это и решением
как то так


Страницы:   1 2 3

Наверх

Титульная страница Поиск, карта сайта Написать письмо