powered by simpleCommunicator - 2.0.49     © 2025 Programmizd 02
Форумы / Программирование [игнор отключен] [закрыт для гостей] / Генерация сочетаний из N по K
25 сообщений из 174, страница 5 из 7
Генерация сочетаний из N по K
    #40039196
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Добавил что-то вроде silent-mode (просто любой третий аргумент командной строки).
Изменил формулу расчета времени. И разделили поток комбинаций и статистику
по раздельным файловым дескрипторам.
Код: 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.
#include <stdint.h>
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <time.h>
#include <stdbool.h>

// Следующее сочетание k элементов диапазона 1...n в массив a[]
// Возвращает true если оно есть
bool nexn_combinations(int* a, int k, int n) {
    for (int i = k - 1, max = n; i >= 0; i--, max--) {
	if (a[i] < 1 || a[i] > max) {  // за границей диапазона
	    printf("ERROR\n");
	    return false;
	}
	if (a[i] < max) {
	    a[i]++;
	    return true;
	}
	if (i > 0) {
	    a[i] = a[i - 1] + 2;
	    if (a[i - 1] == max - 1) {
		a[i]--;
	    }
	}
	for (int j = i + 1; j < k; j++) a[j] = a[j - 1] + 1;
    }
    return false;
}



//**********************************************

int main(int argc, char**argv)
{
    if (argc < 3) {
      fprintf(stderr, "\n  Usage: perm-k-n K N [s]\n\n");
      return 1;
    }
    clock_t start = clock();
    int K = atoi(argv[1]);
    int N = atoi(argv[2]);
    bool silent = argc > 3 ? true : false;
    fprintf(stderr, "C(%d, %d)\n", K,N);
    int a[K];
    for (int i = 0; i < K; i++) a[i] = i + 1;
    int cnt = 0;
    if (silent) {
     fprintf(stderr, "silent_mode = on\n");
     do {
	cnt++;
     } while (nexn_combinations(a, K, N));
    } else {
     do {
	cnt++;
	for(int& i : a) printf("%d ", i);
	printf("\n");
     } while (nexn_combinations(a, K, N));
    }
    fprintf(stderr, "Total: %d Time %.2f s\n", cnt, (float)(clock() - start) / CLOCKS_PER_SEC);
    return 0;



Два из сто тыщ - за 22 секунды.

Код: sql
1.
2.
3.
4.
$ ./perm-k-n.exe 2 100000 s
C(2, 100000)
silent_mode = on
Total: 704982704 Time 22.79 s
...
Рейтинг: 0 / 0
Генерация сочетаний из N по K
    #40039197
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
В исходнике Анатолия такой трюк с silent не прокатывает. Из за рекурсии. В идеале нужно просто написать
два класса с виртуальным методом generate(...) и две реализации с принтом и без.

Вобщем я просто оставлю закоментированным печать векторов сочетаний.

Код: sql
1.
2.
3.
4.
$ /probe-permutation/anatoly-moskovsky$ ./make-run
Time 10.05 s
k=2, n=100000, print=1
total: 4999950000



Пока рекурсия побеждает на длинных N.

Ключи оптимизации и версия компиллятора одинаковые.

Код: sql
1.
2.
$ gcc version 9.3.0 (Ubuntu 9.3.0-17ubuntu1~20.04) 
$ uname -a Linux ryzen-ssd 5.8.0-40-generic #45~20.04.1-Ubuntu SMP Fri Jan 15 11:35:04 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux



Скрипт для сборки тоже одинаковый.
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
#!/bin/bash

rm -f perm-k-n.exe

gcc \
 -O3 -DNDEBUG \
 perm-k-n.cpp \
 -o perm-k-n.exe \
 -lstdc++ && ./perm-k-n.exe 2 100000
...
Рейтинг: 0 / 0
Генерация сочетаний из N по K
    #40039198
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Вот это число надо проверить. Может баг?
mayton

Код: sql
1.
Total: 704982704 Time 22.79 s

...
Рейтинг: 0 / 0
Генерация сочетаний из N по K
    #40039207
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
mayton
Вот это число надо проверить. Может баг?
mayton

Код: sql
1.
Total: 704982704 Time 22.79 s


Ты за разрядность int вылез ))
Поправь тип счетчика
Код: plaintext
1.
2.
3.
int64_t cnt = 0;
...
printf("Total: %lld\n", cnt);



mayton
Код: plaintext
1.
2.
3.
4.
5.
...
    int K = atoi(argv[1]);
...
    int a[K];
...


У тебя это скомпилировалось?
...
Рейтинг: 0 / 0
Генерация сочетаний из N по K
    #40039220
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Да.
...
Рейтинг: 0 / 0
Генерация сочетаний из N по K
    #40039227
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
 long int cnt = 0;
    if (silent) {
     fprintf(stderr, "silent_mode = on\n");
     do {
	cnt++;
     } while (nexn_combinations(a, K, N));
    } else {
     do {
	cnt++;
	for(int& i : a) printf("%d ", i);
	printf("\n");
     } while (nexn_combinations(a, K, N));
    }
 fprintf(stderr, "Total: %ld Time %.2f s\n", cnt, (float)(clock() - start) / CLOCKS_PER_SEC);



Вот так корректно для GCC.
...
Рейтинг: 0 / 0
Генерация сочетаний из N по K
    #40039232
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
mayton
Код: plaintext
1.
fprintf(stderr, "Total: %ld Time %.2f s\n", cnt, (float)(clock() - start) / CLOCKS_PER_SEC);


clock() считает с момента запуска приложения, т.е. у тебя start == 0, можно его выкинуть.
...
Рейтинг: 0 / 0
Генерация сочетаний из N по K
    #40039236
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Пускай будет. На результат почти не влияет.

А если будет пользовательский ввод - то корректнее считать от начала алгоритма а не процедуры main.
...
Рейтинг: 0 / 0
Генерация сочетаний из N по K
    #40039237
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
mayton
Да.

Это динамические (или как их там правильно) массивы на стэке, в стандарте это есть, а MS еще не реализовал, поэтому у меня не компилируется.
...
Рейтинг: 0 / 0
Генерация сочетаний из N по K
    #40039248
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Прикинь я и не заметил. Еще походу удивился. Где там new ?
...
Рейтинг: 0 / 0
Генерация сочетаний из N по K
    #40039273
Aleksandr Sharahov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
mayton
Ну я скоро запутаюсь в исходниках.


Все мои предыдущие исходники отправляются в корзину.
Вот этот генерирует 6 из 100 на i7-7700 за 453 msec:
Код: 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.
function GenerateCombinationDesc(p: pIntegerArray; n, k: integer): integer;
var
  i: integer;
begin;
  Result:=0;
  i:=k;
  dec(i);
  while true do begin;
    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;
    repeat;
      inc(i); if i>=k then exit;
      n:=p[i];
      until i<n;
    end;
  end;



как вызывать:
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
procedure ShowCombinationDesc(p: pIntegerArray; len: integer);
var
  s: AnsiString;
  i: integer;
begin;
  for i:=0 to len-1 do s:=s+AnsiChar(Ord('0')+p[i]);
  //Form1.Memo1.Lines.Add(s);
  WriteLn(s);
  end;

var
  n, k: integer;
begin;
  n:=100; k:=6; 
  SetLength(c, k);
  cnt:=GenerateCombinationDesc(@c[0], n, k);
end.
...
Рейтинг: 0 / 0
Генерация сочетаний из N по K
    #40039285
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Aleksandr Sharahov

Все мои предыдущие исходники отправляются в корзину.

это прекрасно. Вот что брейншторм делает!

Сегодня вечером попробую собрать на fpc.
...
Рейтинг: 0 / 0
Генерация сочетаний из N по K
    #40039553
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Я вот думаю можно ли как-то произвольное преобразование сделать?
Т.е. знаешь номер по-порядку и преобразуешь его в соответствующее ему сочетание и наоборот. Типа как перевод из одной системы счисления в другую.
По идее это тоже разновидность системы счисления, но разные разряды имеют разный вес.
...
Рейтинг: 0 / 0
Генерация сочетаний из N по K
    #40039560
Aleksandr Sharahov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dima T
Я вот думаю можно ли как-то произвольное преобразование сделать?
Т.е. знаешь номер по-порядку и преобразуешь его в соответствующее ему сочетание и наоборот. Типа как перевод из одной системы счисления в другую.
По идее это тоже разновидность системы счисления, но разные разряды имеют разный вес.


1. В английской вики приводятся варианты нумерации, фактически имитирующие генерацию.
2. Можно старое сочетание использовать для генерации нового.
3. Можно рассмотреть комбинацию 1 и 2 - несплошную нумерацию,
когда у номера комбинации единичные биты соответствуют
выбранным элементам множества.
...
Рейтинг: 0 / 0
Генерация сочетаний из N по K
    #40039570
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dima T
Я вот думаю можно ли как-то произвольное преобразование сделать?
Т.е. знаешь номер по-порядку и преобразуешь его в соответствующее ему сочетание и наоборот. Типа как перевод из одной системы счисления в другую.
По идее это тоже разновидность системы счисления, но разные разряды имеют разный вес.

Можно для все последовательности посчитать каждый 1000-й элемент. И назвать его опорным.
И положить в табличку. Порядковый номер => опорный элемент. И дальше если нужно например
100000-й сочетание - то ищем бинарным поиском по табличке порядковый номер. И потом опорный
и дальше перемоткой вперед добиваем столько позиций сколько надо.
...
Рейтинг: 0 / 0
Генерация сочетаний из N по K
    #40039926
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
UP. Привет всем.

Прошу прощения за отсутсвие. Я помню что обещал. Просто неделька была бешеная. ПОЦ-ы. Стартапы.
Тоесть POC-s. Я только-только отбился от всех.

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

Почитал и ничего не понял если честно, еще раз почитаю
Aleksandr Sharahov
2. Можно старое сочетание использовать для генерации нового.

У меня в коде так и происходит. next_combinations() получает на вход массив с текущей комбинацией и преобразует ее в следующую.

mayton
Можно для все последовательности посчитать каждый 1000-й элемент. И назвать его опорным.
И положить в табличку. Порядковый номер => опорный элемент. И дальше если нужно например
100000-й сочетание - то ищем бинарным поиском по табличке порядковый номер. И потом опорный
и дальше перемоткой вперед добиваем столько позиций сколько надо.

Можно, эдакие радужные таблицы получатся, но их считать надо или хранить.

Я пытался в уме формулу вывести для небольшой последовательности типа С(2,5) для 2-х вроде должно получиться, а если С(3,5) то тут уже сложнее, надо поизучать в экселе.
...
Рейтинг: 0 / 0
Генерация сочетаний из N по K
    #40039940
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dima T, кстати идеи которые у нас звучали в топике простых чисел
применимы и для последовательности сочетаний.

Например такое

Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
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
1 3 4 6
1 3 5 6
1 4 5 6
2 3 4 5
2 3 4 6
2 3 5 6
2 4 5 6
3 4 5 6



хорошо сжимается дифференциальным кодированием или деревом префиксов.

Как бегать поиском по сжатой структуре - отдельная задача.
...
Рейтинг: 0 / 0
Генерация сочетаний из N по K
    #40040001
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
По поводу Delphi, FreePascal.

Я синтаксис программы не помню. Кажется она начинается с program и заканчивается end.

Сделал так.

Код: 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.
program perm_k_n;

function GenerateCombinationDesc(p: pIntegerArray; n, k: integer): integer;
var
  i: integer;
begin;
  Result:=0;
  i:=k;
  dec(i);
  while true do begin;
    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;
    repeat;
      inc(i); if i>=k then exit;
      n:=p[i];
      until i<n;
    end;
  end;

procedure ShowCombinationDesc(p: pIntegerArray; len: integer);
var
  s: AnsiString;
  i: integer;
begin;
  for i:=0 to len-1 do s:=s+AnsiChar(Ord('0')+p[i]);
  //Form1.Memo1.Lines.Add(s);
  WriteLn(s);
  end;

var
  n, k: integer;
begin;
  n:=100; k:=6; 
  SetLength(c, k);
  cnt:=GenerateCombinationDesc(@c[0], n, k);
end.

ens.



Сборочный скриптик.

Код: sql
1.
2.
3.
4.
5.
6.
#!/bin/bash

rm -f perm-k-n.exe

fpc -CX -O3 -XX -vewnhi -Fi. -Fu. -FU. perm-k-n.lpr \
  && mv perm-k-n perm-k-n.exe



И лог ошибок. Кто знает как исправить?

Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
Hint: Start of reading config file /etc/fpc.cfg
Hint: End of reading config file /etc/fpc.cfg
Free Pascal Compiler version 3.0.4+dfsg-23 [2019/11/25] for x86_64
Copyright (c) 1993-2017 by Florian Klaempfl and others
Target OS: Linux for x86-64
Compiling perm-k-n.lpr
perm-k-n.lpr(7,3) Error: Identifier not found "Result"
perm-k-n.lpr(13,13) Error: Incompatible types: got "SmallInt" expected "IntegerArray"
perm-k-n.lpr(18,13) Error: Incompatible types: got "SmallInt" expected "IntegerArray"
perm-k-n.lpr(19,11) Error: Identifier not found "Result"
perm-k-n.lpr(24,11) Error: Incompatible types: got "IntegerArray" expected "SmallInt"
perm-k-n.lpr(34,46) Error: Operator is not overloaded: "Byte" + "IntegerArray"
perm-k-n.lpr(43,13) Error: Identifier not found "c"
perm-k-n.lpr(44,3) Error: Identifier not found "cnt"
perm-k-n.lpr(44,33) Error: Identifier not found "c"
perm-k-n.lpr(47,1) Fatal: There were 9 errors compiling module, stopping
Fatal: Compilation aborted
Error: /usr/bin/ppcx64 returned an error exitcode
...
Рейтинг: 0 / 0
Генерация сочетаний из N по K
    #40040005
Aleksandr Sharahov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
mayton,

на дельфи вот так все работает

Код: 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.
52.
53.
program perm_k_n;

{$APPTYPE CONSOLE}

uses
  SysUtils;

procedure ShowCombinationDesc(p: pIntegerArray; len: integer);
var
  s: AnsiString;
  i: integer;
begin;
  for i:=0 to len-1 do s:=s+AnsiChar(Ord('0')+p[i]);
  WriteLn(s);
  end;

function GenerateCombinationDesc(p: pIntegerArray; n, k: integer): integer;
var
  i: integer;
begin;
  Result:=0;
  i:=k;
  dec(i);
  while true do begin;
    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;
    repeat;
      inc(i); if i>=k then exit;
      n:=p[i];
      until i<n;
    end;
  end;

var
  c: array of integer;
  n, k, cnt: integer;
begin;
  n:=100; k:=6;
  //n:=6; k:=4;
  SetLength(c, k);
  cnt:=GenerateCombinationDesc(@c[0], n, k);
  WriteLn(cnt);
  ReadLn
end.

...
Рейтинг: 0 / 0
Генерация сочетаний из N по K
    #40040008
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
mayton
хорошо сжимается дифференциальным кодированием или деревом префиксов.

В идеале не должно быть ничего из упомянутого. Надо просто формулу для перевода какого-то значения, например 12345, в счисление C(K,N) и обратно
...
Рейтинг: 0 / 0
Генерация сочетаний из N по K
    #40040011
Aleksandr Sharahov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dima T
mayton
хорошо сжимается дифференциальным кодированием или деревом префиксов.

В идеале не должно быть ничего из упомянутого. Надо просто формулу для перевода какого-то значения, например 12345, в счисление C(K,N) и обратно


похоже формулы нету, есть алгоритмы, которые позволяют его вычислить для сочетания и наоборот.
Суть всех методов - сведение к сумме задач меньшей размерности.
...
Рейтинг: 0 / 0
Генерация сочетаний из N по K
    #40040014
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Aleksandr Sharahov,

Все таки разница между делфи и фпс большая

Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
Hint: Start of reading config file /etc/fpc.cfg
Hint: End of reading config file /etc/fpc.cfg
Free Pascal Compiler version 3.0.4+dfsg-23 [2019/11/25] for x86_64
Copyright (c) 1993-2017 by Florian Klaempfl and others
Target OS: Linux for x86-64
Compiling perm-k-n.lpr
perm-k-n.lpr(3,2) Warning: APPTYPE is not supported by the target OS
perm-k-n.lpr(13,46) Error: Operator is not overloaded: "Byte" + "IntegerArray"
perm-k-n.lpr(21,3) Error: Identifier not found "Result"
perm-k-n.lpr(27,13) Error: Incompatible types: got "SmallInt" expected "IntegerArray"
perm-k-n.lpr(32,13) Error: Incompatible types: got "SmallInt" expected "IntegerArray"
perm-k-n.lpr(33,11) Error: Identifier not found "Result"
perm-k-n.lpr(38,11) Error: Incompatible types: got "IntegerArray" expected "SmallInt"
perm-k-n.lpr(54) Fatal: There were 6 errors compiling module, stopping
Fatal: Compilation aborted
Error: /usr/bin/ppcx64 returned an error exitcode
...
Рейтинг: 0 / 0
Генерация сочетаний из N по K
    #40040020
Aleksandr Sharahov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
mayton,

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

{$APPTYPE CONSOLE} надо убрать

нижний блок можно попробовать заменить на
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
var
  c: array of integer;
  p: pointer;           
  n, k, cnt: integer;
begin;
  n:=100; k:=6;
  SetLength(c, k);
  p:=@c[0];
  cnt:=GenerateCombinationDesc(p, n, k);
  WriteLn(cnt);
  ReadLn;
end.
...
Рейтинг: 0 / 0
25 сообщений из 174, страница 5 из 7
Форумы / Программирование [игнор отключен] [закрыт для гостей] / Генерация сочетаний из N по K
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


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