powered by simpleCommunicator - 2.0.49     © 2025 Programmizd 02
Форумы / Программирование [игнор отключен] [закрыт для гостей] / Генерация сочетаний из N по K
24 сообщений из 174, страница 7 из 7
Генерация сочетаний из N по K
    #40040728
Aleksandr Sharahov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Генерацию длинных сочетаний можно оптимизировать за счет более быстрого формирования хвоста
в случае, когда он состоит из серии последовательных элементов.
Например, для каждого из следующих переходов достаточно изменить 1 элемент:
02348
01348
01248
01238

Длинные сочетания следующий алгоритм на Delphi генерирует быстрее предыдущего более, чем в 2 pаза:
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
function GenerateCombinationDesc2(p: pIntegerArray; n, k: integer): integer;
var
  i: integer;
begin;
  Result:=0;
  i:=k;
  while true do begin;
    dec(i);
    while i>0 do begin;
      dec(n);
      p[i]:=n;
      dec(i);
      end;
    repeat;
      dec(n);
      p[0]:=n;
      inc(Result);                  //подсчет сочетаний
      //ShowCombinationDesc(p, k);  //обработка очередного сочетания
      until n<=0;
    while true do begin;
      repeat;
        inc(i); if i>=k then exit;
        n:=p[i];
        until i<n;
      dec(n);
      p[i]:=n;
      if i<n then break;
      inc(Result);                  //подсчет сочетаний
      //ShowCombinationDesc(p, k);  //обработка очередного сочетания
      end;
    end;
  end;
...
Рейтинг: 0 / 0
Генерация сочетаний из N по K
    #40040845
exp98
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
С псевдооптимизациями я понял.

Теперь вопрос по способам использования. Данная версия заточена на массовый стрим сочетаний.
А если хочется ... не уверен, что правильно, реэнтерабельности?
Аналогично next_permutation()
Сильно надо курочить для переделки под сохранение последнего состояния циклов?
...
Рейтинг: 0 / 0
Генерация сочетаний из N по K
    #40040848
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
exp98
А если хочется ... не уверен, что правильно, реэнтерабельности?
Аналогично next_permutation()

22268624
...
Рейтинг: 0 / 0
Генерация сочетаний из N по K
    #40043847
__Avenger__
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Мой вариант:

Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
program TestGenComb;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.SysUtils;

procedure Combination(const AElement: TArray<Integer>; const ALen, AStartPos: Integer; var AResult: TArray<Integer>; const ALenElement, ALenResult: Integer; var ACount: Integer); inline;
var
  Index: Integer;
  ANum: Integer;
begin
  if ALen < 1 then
  begin
    Inc(ACount);
    for ANum in AResult do
      Write(ANum, ' ');
    WriteLn;
    Exit;
  end;
  for Index := AStartPos to ALenElement - ALen do
  begin
    AResult[ALenResult - ALen] := AElement[Index];
    Combination(AElement, ALen - 1, Index + 1, AResult, ALenElement, ALenResult, ACount);
  end;
end;

var
  FElement,
  FResult: TArray<Integer>;
  FCount, I: Integer;

begin
  try
    FCount := 0;
    SetLength(FElement, 10);
    for I := Low(FElement) to High(FElement) do
      FElement[I] := I + 1;

    SetLength(FResult, 6);
    Combination(FElement, Length(FResult), 0, FResult, Length(FElement), Length(FResult), FCount);

    WriteLn(FCount);
    ReadLn;
  except
    on E: Exception do
      WriteLn(E.ClassName, ': ', E.Message);
  end;
end.

...
Рейтинг: 0 / 0
Генерация сочетаний из N по K
    #40043851
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Пора наверное делать сравнительную табличку.
Все реализации. И скорость генерации.
...
Рейтинг: 0 / 0
Генерация сочетаний из N по K
    #40043888
__Avenger__
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Aleksandr Sharahov
Генерацию длинных сочетаний можно оптимизировать за счет более быстрого формирования хвоста
в случае, когда он состоит из серии последовательных элементов.
Например, для каждого из следующих переходов достаточно изменить 1 элемент:
02348
01348
01248
01238

Длинные сочетания следующий алгоритм на Delphi генерирует быстрее предыдущего более, чем в 2 pаза:
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
function GenerateCombinationDesc2(p: pIntegerArray; n, k: integer): integer;
var
  i: integer;
begin;
  Result:=0;
  i:=k;
  while true do begin;
    dec(i);
    while i>0 do begin;
      dec(n);
      p[i]:=n;
      dec(i);
      end;
    repeat;
      dec(n);
      p[0]:=n;
      inc(Result);                  //подсчет сочетаний
      //ShowCombinationDesc(p, k);  //обработка очередного сочетания
      until n<=0;
    while true do begin;
      repeat;
        inc(i); if i>=k then exit;
        n:=p[i];
        until i<n;
      dec(n);
      p[i]:=n;
      if i<n then break;
      inc(Result);                  //подсчет сочетаний
      //ShowCombinationDesc(p, k);  //обработка очередного сочетания
      end;
    end;
  end;



Ваш алгоритм делает перестановки не из чисел массива, а просто уменьшая и увеличивая начальные числа на 1. Это неправильно, должны быть перестановки элементов массива.
...
Рейтинг: 0 / 0
Генерация сочетаний из N по K
    #40043899
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
__Avenger__
Ваш алгоритм делает перестановки не из чисел массива, а просто уменьшая и увеличивая начальные числа на 1. Это неправильно, должны быть перестановки элементов массива.

Все верно, так получилось что исходно все решали задачу перестановок диапазона от 1 до N, где N задается на входе.
Будем считать эти числа индексами элементов массива начиная с 1.
...
Рейтинг: 0 / 0
Генерация сочетаний из N по K
    #40044843
Gennadiy Usov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Здесь на топике рассматриваются только перестановки N чисел из M чисел?

А если ещё рассматривать все комбинации чисел из M чисел:
по 1, по 2, по 3 и т.д. за один прогон
...
Рейтинг: 0 / 0
Генерация сочетаний из N по K
    #40044846
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Gennadiy Usov
А если ещё рассматривать все комбинации чисел из M чисел:
по 1, по 2, по 3 и т.д. за один прогон

Если еще добавить используемое тут условие монотонного возрастания, то такая комбинация одна для каждого М.
...
Рейтинг: 0 / 0
Генерация сочетаний из N по K
    #40044850
Aleksandr Sharahov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Gennadiy Usov
Здесь на топике рассматриваются только перестановки N чисел из M чисел?

А если ещё рассматривать все комбинации чисел из M чисел:
по 1, по 2, по 3 и т.д. за один прогон


тогда просто M-битный счетчик: K=K+1
...
Рейтинг: 0 / 0
Генерация сочетаний из N по K
    #40044851
Gennadiy Usov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Кстати, если найдена одна комбинация N из М, то тут же есть одна комбинация (М - N) из М

Или проще (и быстрее) в едином цикле (циклах)
...
Рейтинг: 0 / 0
Генерация сочетаний из N по K
    #40044935
Gennadiy Usov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
нашел в Питоне подпрограмму:

itertools.combinations(iterable, [r]) - комбинации длиной r из iterable без повторяющихся элементов.
...
Рейтинг: 0 / 0
Генерация сочетаний из N по K
    #40044940
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Gennadiy Usov
нашел в Питоне подпрограмму:

itertools.combinations(iterable, [r]) - комбинации длиной r из iterable без повторяющихся элементов.

Нам тут надо чуть сложнее, комбинация должна быть монотонно возрастающая, т.е. надо {1,2,3} и не надо {1,3,2}, {3,2,1} и т.п.
...
Рейтинг: 0 / 0
Генерация сочетаний из N по K
    #40044943
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Обсуждать питонские комбинаторщики имеет смысл только с их исходным кодом и если они несут идею лучше
чем мы уже здесь рассмотрели.
...
Рейтинг: 0 / 0
Генерация сочетаний из N по K
    #40044945
Gennadiy Usov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
mayton
Обсуждать питонские комбинаторщики имеет смысл только с их исходным кодом
и если они несут идею лучше чем мы уже здесь рассмотрели.
Для оценочных вычислений на небольших массивах удобно.

Массив из 25 чисел обрабатывается за 5 сек. на моём компе.
33554430 вариантов.
...
Рейтинг: 0 / 0
Генерация сочетаний из N по K
    #40044946
Gennadiy Usov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Dima T
Gennadiy Usov
нашел в Питоне подпрограмму:
itertools.combinations(iterable, [r]) - комбинации длиной r из iterable без повторяющихся элементов.

Нам тут надо чуть сложнее, комбинация должна быть монотонно возрастающая,
т.е. надо {1,2,3} и не надо {1,3,2}, {3,2,1} и т.п.
Если исходный массив монотонно возрастающий (убывающий),
то и получаемые массивы будут то же монотонно возрастающие (убывающие)

Проверено
...
Рейтинг: 0 / 0
Генерация сочетаний из N по K
    #40044947
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Без исходников - неинтересно.
...
Рейтинг: 0 / 0
Генерация сочетаний из N по K
    #40045190
Фотография Anatoly Moskovsky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Вот код реализации itertools.combination: https://github.com/python/cpython/blob/master/Modules/itertoolsmodule.c#L2674
Алгоритм похож на Dima T

Алгоритм скопировал в свой код.
Работает почти в два раза медленнее моего.
Впрочем там видны места потенциальных оптимизаций.
Может и можно его ускорить.
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
#include <iostream>
#include <vector>

#define LIKELY(x)       __builtin_expect(!!(x), 1)
#define UNLIKELY(x)     __builtin_expect(!!(x), 0)


class PythonCombinator
{
public:
    PythonCombinator(size_t k, std::vector<int> items, bool print)
        : k(k)
        , n(items.size())
        , items(std::move(items))
        , print(print)
    {
        curr.resize(k);
        for (size_t i = 0; i < k; i++) {
            curr[i] = i;
        }
    }

    void generate() noexcept
    {
        std::cout << "k=" << k << ", n=" << n << ", print=" << print << "\n";
        size_t count = generate_impl();
        std::cout << "total: " << count << "\n";
    }

private:
    // алгоритм
    bool generate_one() noexcept
    {
        ssize_t i, j;
        /* Scan indices right-to-left until finding one that is not
           at its maximum (i + n - r). */
        for (i = k - 1; i >= 0 && curr[i] == i + n - k; i--)
            ;

        /* If i is negative, then the indices are all at
           their maximum value and we're done. */
        if (i < 0)
            return false;

        /* Increment the current index which we know is not at its
           maximum.  Then move back to the right setting each index
           to its lowest possible value (one higher than the index
           to its left -- this maintains the sort order invariant). */
        curr[i]++;
        for (j = i + 1; j < k; j++)
            curr[j] = curr[j - 1] + 1;

        return true;
    }

    size_t generate_impl() noexcept __attribute((noinline))
    {
        size_t count = 0;
		count++;
		print_current();
        while (generate_one()) {
            count++;
            print_current();
        }

        return count;
    }

    void print_current() noexcept 
    {
        if (UNLIKELY(print)) {
            for (size_t i = 0; i < k; i++) {
                std::cout << items[curr[i]] << " ";
            }
            std::cout << "\n";
        }
    }

private:
    const size_t k;
    const size_t n;
    const std::vector<int> items;
    const bool print;
    std::vector<size_t> curr;
    size_t count = 0;
};


std::vector<int> iota(size_t n)
{
    std::vector<int> rv(n);
    for (size_t i = 0; i < n; i++) {
        rv[i] = i + 1;
    }
    return rv;
}

int main(int argc, char* argv[])
{
    std::cout.sync_with_stdio(false);
    size_t k = 3;
    int n = 4;
    bool print = true;
    if (argc > 2) {
        k = atol(argv[1]);
        n = atol(argv[2]);
    }
    if (argc > 3) {
        print = argv[3][0] == 'p';
    }
    PythonCombinator comb{k, iota(n), print};
    comb.generate();
    return 0;
}

...
Рейтинг: 0 / 0
Генерация сочетаний из N по K
    #40045216
Aleksandr Sharahov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
до кучи добавлю питонизацию алгоритма 22272948 ,
перебирает комбинации по 6 из 100 за 84 сек:

Код: python
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
def gen2(n, k):
  p=list(range(n-k,n))
  Result=0
  i=k
  while 1:
    i-=1
    while i>0:
      n-=1
      p[i]=n
      i-=1
    while 1:
      n-=1
      p[0]=n
      Result+=1
      #print(p)  #обработка очередного сочетания
      if n<=0:
        break
    while 1:
      while 1:
        i+=1 
        if i>=k:
          return Result
        n=p[i]
        if i<n:
          break
      n-=1
      p[i]=n
      if i<n:
        break
      Result+=1
      #print(p)  #обработка очередного сочетания

import time
t1=time.time()
ct=gen2(100,6)
t2=time.time()
print(ct, round(t2-t1,3))
...
Рейтинг: 0 / 0
Генерация сочетаний из N по K
    #40045220
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Aleksandr Sharahov, спасибо. Насколько я понимаю CPython - это и есть реализация Python3.
...
Рейтинг: 0 / 0
Генерация сочетаний из N по K
    #40045221
Aleksandr Sharahov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
mayton
Aleksandr Sharahov, спасибо. Насколько я понимаю CPython - это и есть реализация Python3.


я тоже так думаю )

Тут интересно то, что вызов их итератора для подсчета комбинаций
оказывается сравним по времени и даже медленнее (90 сек),
чем родная программа на питоне.
...
Рейтинг: 0 / 0
Генерация сочетаний из N по K
    #40045223
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Ни знаю. Я ни разу ни кайфонул от Питона. Если нужен был универсальный язык-клей - то взяли-бы Lua например.
А в этом Питоне есть странные вырви-глазные ключевые слова.

Код: sql
1.
__init__



например. Зачем так сделано? ХЗ. Язык должен быть эстетически красив и радовать. Причем масса других ключевых
слов - с маленькой буквы а True/False почему-то с большой.
...
Рейтинг: 0 / 0
Генерация сочетаний из N по K
    #40045237
exp98
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
mayton
Язык должен быть эстетически красив и радовать.
Это точно не про с++. И не про яву.
Подумал сразу, что если в известном поизведении LA Creazione в дающую справа руку вложить мордофон? Веление времени.
Что станет с эстетикой?
И вообще, по-мойму из 3-х свойств ЯП (красота, радость, скорость) осуществимы не более 2-х.
...
Рейтинг: 0 / 0
Генерация сочетаний из N по K
    #40045286
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Ruby мог-бы быть в списке красивых языков.
...
Рейтинг: 0 / 0
24 сообщений из 174, страница 7 из 7
Форумы / Программирование [игнор отключен] [закрыт для гостей] / Генерация сочетаний из N по K
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]