powered by simpleCommunicator - 2.0.49     © 2025 Programmizd 02
Форумы / Программирование [игнор отключен] [закрыт для гостей] / Генерация сочетаний из N по K
25 сообщений из 174, страница 2 из 7
Генерация сочетаний из N по K
    #40038465
Фотография Anatoly Moskovsky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dima T
а "за границей диапазона" это контроль ошибок, его надо оставить.

Это должен быть assert() включаемый только в дебаг сборках.
Потому что в это отладочный код.
...
Рейтинг: 0 / 0
Генерация сочетаний из N по K
    #40038473
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Anatoly Moskovsky
Dima T
а "за границей диапазона" это контроль ошибок, его надо оставить.

Это должен быть assert() включаемый только в дебаг сборках.
Потому что в это отладочный код.

Может и так, но эти 7% мало что меняют. Тут важно оценить сложность алгоритма, ясно что не O(1). Например если потребуется 5 лет, то будет пофиг 5 лет или 5 лет и 4 месяца.
...
Рейтинг: 0 / 0
Генерация сочетаний из N по K
    #40038501
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dima T, под gcc выдает варнинг

Код: sql
1.
2.
3.
4.
5.
6.
7.
perm-k-n.cpp: In function ‘int main(int, char**)’:
perm-k-n.cpp:45:29: warning: format ‘%d’ expects argument of type ‘int’, but argument 3 has type ‘clock_t’ {aka ‘long int’} [-Wformat=]
   45 |     printf("Total: %d Time %d ms", cnt, clock());
      |                            ~^           ~~~~~~~
      |                             |                |
      |                             int              clock_t {aka long int}
      |                            %ld
...
Рейтинг: 0 / 0
Генерация сочетаний из N по K
    #40038505
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Anatoly Moskovsky
mayton
Что нам интересно рассматривать:
1. Большие величиные N. Например от 100.


А в чем сложность больших N? Разве что переполнение стека при рекурсивной реализации.
Но там вообще глубина стека равна K (размер сочетаний), а не N.
А К у нас вряд ли будет достаточно большим чтобы переполнить стек.

В данном конкретном алгоритме переполнение стека нам не грозит. Слишком малые у нас запросы.
А на больших - мы дождемся финала когда остынет солнце.

Что интересовало? Некие общие подходы к комбинаторным алгоритмам. Генераторы последовательностей.
Ленивые списки. Хвостовая рекурсия в продолжение моего одноименного топика. (Всегда-ли возможно?)
...
Рейтинг: 0 / 0
Генерация сочетаний из N по K
    #40038519
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Пока быстрее работает рекурсивный алгоритм Анатолия. На генерации 6 из 45 занимает меньше 1 секунды
против 9 секунд итеративного метода Димы.

В коде Анатолия я только счетчик перенес из принта в основную функцию потому-что при отключени вывода
на печать - выключается и подсчет найденных сочетаний.

Код: 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.
    void generate(size_t pos, size_t val) noexcept
    {
        const size_t limit = n - k + pos + 1;
        for (; val < limit; val++) {
            curr[pos] = val;
            if (pos == k - 1) {
                //print_current();    
                count++;
            }
            else {
                generate(pos + 1, val + 1);
            }
        }
    }

    void print_current() noexcept
    {
        // deleted
        if (print) {
            for (size_t i = 0; i < k; i++) {
                std::cout << items[curr[i]] << " ";
            }
            std::cout << "\n";
        }
    }
...
Рейтинг: 0 / 0
Генерация сочетаний из N по K
    #40038522
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Александр. Я про твой код не забыл. Просто пока не хватает терпенья оформить все формальности для того чтоб собрать
туловище алгоритма.

make.sh
Код: sql
1.
2.
3.
4.
5.
#!/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.
$ ./make.sh
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(10,34) Warning: Local variable "s" of a managed type does not seem to be initialized
perm-k-n.lpr(53,1) Fatal: Syntax error, "BEGIN" expected but "identifier GENERATECOMBINATIONS" found
Fatal: Compilation aborted
Error: /usr/bin/ppcx64 returned an error exitcode



perm-k-n.lpr - это последний сорс который ты публиковал.

Уж извини если я иногда - нетерпеливый.
...
Рейтинг: 0 / 0
Генерация сочетаний из N по K
    #40038551
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Тюнинганул алгоритм, заменил проверку на assert(), но стало медленнее (( 1.96 сек вместо 1.67 тут 22268468
исходник
Код: 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.
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <assert.h>

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

//**********************************************
int main(int argc, char**argv)
{
	int k, n;
	if (argc > 2) {
		k = atoi(argv[1]);
		n = atoi(argv[2]);
	} else {
		printf("Too few arguments\n");
		return 0;
	}

	printf("C(%d, %d)\n", k, n);
	int *a = new int[k];
	for (int i = 0; i < k; i++) a[i] = i + 1;
	int cnt = 0;
	do {
		cnt++;
#ifdef _DEBUG
		for (int i = 0; i < k; i++) printf("%d ", a[i]);
		printf("\n");
#else
		if((cnt & 0x3FFFFFF) == 0) printf("Total: %d\r", cnt);
#endif
	} while (nexn_combinations(a, k, n));

	printf("Total: %d\n", cnt);
#if defined(_WIN32) || defined(_WIN64)
	printf("Time %d ms", clock());
#endif
	delete[] a;
	return 0;
}


mayton
Пока быстрее работает рекурсивный алгоритм Анатолия. На генерации 6 из 45 занимает меньше 1 секунды
против 9 секунд итеративного метода Димы.

Затестил алгоритм Анатолия без вывода - 1.63 сек. Странно конечно что рекурсия быстрее, но не в разы. Проверь, может с разными ключами компилировал.

PS Оказалось эта проверка отъедает 0.12 сек, можно закаментить, без нее 1.84 сек.
Код: plaintext
1.
if((cnt & 0x3FFFFFF) == 0) printf("Total: %d\r", cnt);



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

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

И сам current вектор - глобальный и модифицируется на каждом рекуррентном вызове.

Я думаю что мы достигли хорошей величины перформанса и дальше - узким местом
будет просто передача найденных сочетаний в consumer или в то приложение
которое будет его юзать.

Здесь я хотел-бы это сделать на streams/actors/ или каких-то асинхронных технологиях
через кольцевой буфер.

Тоесть чтобы генерация сочетаний шла отдельным потоком а уже их извлечение отдельно.

Работа с STDOUT - это конечно ужас-ужас но пускай пока она будет как основной вариант
межпроцессного протокола.

И в данной задаче (которая удачно ложится на списки ФП) я еще для себя хотел реализовать
ее на Haskell/Lisp если будет время.
...
Рейтинг: 0 / 0
Генерация сочетаний из N по K
    #40038635
Фотография Anatoly Moskovsky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
mayton
В идеале у нас получается что вся полезная информация по рекурсии лежит в стеке.
Это два целых числа.

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

Вот еще вчера наклепал нерекурсивный алгоритм с явным стеком.
Скорость чуть хуже рекурсивного со стеком на основе std::deque и чуть лучше с boost::static_vector (но жесткий лимит на глубину стека).

Код: sql
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.
#include <iostream>
#include <stack>
#include <vector>

//#include <boost/container/small_vector.hpp>
//#include <boost/container/static_vector.hpp>

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


class NonRecursiveCombinator
{
public:
    NonRecursiveCombinator(size_t k, std::vector<int> items, bool print)
        : k(k)
        , n(items.size())
        , items(std::move(items))
        , print(print)
    {
        curr.resize(k);
    }

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

private:
    // алгоритм
    void generate_impl() noexcept
    {
        struct State {
            size_t val;
        };
        //std::stack<State, boost::container::small_vector<State, 1000>> stack;
        //std::stack<State, std::vector<State>> stack;
        std::stack<State> stack; // deque; 2nd fastest
        //std::stack<State, boost::container::static_vector<State, 1000>> stack; // fastest
        size_t pos = 0;
        size_t limit = n - k + pos + 1;
        size_t val = 0;
        while (true) {
            for (; val < limit; val++) {
                curr[pos] = val;
                if (pos == k - 1) {
                    print_current();
                }
                else {
                    stack.push({val + 1});
                    pos++;
                    limit++;
                }
            }
            if (stack.empty())
                break;
            val = stack.top().val;
            stack.pop();
            pos--;
            limit--;
        }
    }

    void print_current() noexcept
    {
        count++;
        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';
    }
    NonRecursiveCombinator comb{k, iota(n), print};
    comb.generate();
    return 0;
}


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

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

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

Код: sql
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.
#include <iostream>
#include <vector>

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


class NonRecursiveCombinator
{
public:
    NonRecursiveCombinator(size_t k, std::vector<int> items, bool print)
        : k(k)
        , n(items.size())
        , items(std::move(items))
        , print(print)
    {
        curr.resize(k);
    }

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

private:
    // алгоритм
    void generate_impl() noexcept
    {
        size_t pos = 0;
        size_t limit = n - k + pos + 1;
        size_t val = 0;
        while (true) {
            for (; val < limit; val++) {
                curr[pos] = val;
                if (pos == k - 1) {
                    print_current();
                }
                else {
                    pos++;
                    limit++;
                }
            }
            if (pos == 0)
                break;
            pos--;
            limit--;
            val = curr[pos] + 1;
        }
    }

    void print_current() noexcept
    {
        count++;
        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';
    }
    NonRecursiveCombinator comb{k, iota(n), print};
    comb.generate();
    return 0;
}


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

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

PS Оказалось эта проверка отъедает 0.12 сек, можно закаментить, без нее 1.84 сек.

ОК спасибо.
Проверю вечером на своём AMD. Щас сижу на ограниченном десктопе где неудобно собирать и бенчмаркать.
...
Рейтинг: 0 / 0
Генерация сочетаний из N по K
    #40038661
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
mayton
Пока быстрее работает рекурсивный алгоритм Анатолия. На генерации 6 из 45 занимает меньше 1 секунды
против 9 секунд итеративного метода Димы.

Я потестил 6 из 45 считает 18 мс. Что-то у тебя не то с замером или компилятором.

Вот самый быстрый код. С(6,100) за 1.2 сек. Только для каждого k надо будет отдельно код написать

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
// Все сочетания из 1...n по 6
void all_combinations_6(int n) {
	printf("C(6, %d)\n", n);
	int cnt = 0;
	for (int i1 = 1; i1 <= n - 5; i1++)
		for (int i2 = i1 + 1; i2 <= n - 4; i2++)
			for (int i3 = i2 + 1; i3 <= n - 3; i3++)
				for (int i4 = i3 + 1; i4 <= n - 2; i4++)
					for (int i5 = i4 + 1; i5 <= n - 1; i5++)
						for (int i6 = i5 + 1; i6 <= n; i6++)
						{
							//printf("%d %d %d %d %d %d\n", i1, i2, i3, i4, i5, i6);
							cnt++;
							if ((cnt & 0x3FFFFFF) == 0) printf("Total: %d\r", cnt);
						}
	printf("Total: %d\n", cnt);
}


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

Код: plaintext
1.
if((cnt & 0x3FFFFFF) == 0) printf("Total: %d\r", cnt);


Не может этого быть. Маска + сравнение... Скорее всего тормозит printf даже при печати в /dev/null
ведь ему надо сделать десятичное форматирование cnt и еще ряд каких-то блокировок и фиксаций в разделяемый
объект стандартного вывода.
...
Рейтинг: 0 / 0
Генерация сочетаний из N по K
    #40038667
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dima T

Только для каждого k надо будет отдельно код написать

Ахахах!
...
Рейтинг: 0 / 0
Генерация сочетаний из N по K
    #40038668
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dima T
mayton
Пока быстрее работает рекурсивный алгоритм Анатолия. На генерации 6 из 45 занимает меньше 1 секунды
против 9 секунд итеративного метода Димы.

Я потестил 6 из 45 считает 18 мс. Что-то у тебя не то с замером или компилятором.

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

Код: plaintext
1.
if((cnt & 0x3FFFFFF) == 0) printf("Total: %d\r", cnt);


Не может этого быть. Маска + сравнение... Скорее всего тормозит printf даже при печати в /dev/null
ведь ему надо сделать десятичное форматирование cnt и еще ряд каких-то блокировок и фиксаций в разделяемый
объект стандартного вывода.

Для C(6, 100) эта строчка выполняется 1.2 миллиарда раз. Т.е. (cnt & 0x3FFFFFF) == 0 выполняется со скоростью примерно 10 миллиардов раз в секунду.
...
Рейтинг: 0 / 0
Генерация сочетаний из N по K
    #40038671
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
mayton
Dima T

Только для каждого k надо будет отдельно код написать

Ахахах!

Шаблонам же можно кучу однотипных функций компилировать, а мы чем хуже. Можно генератор кода написать

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

mayton
Я все собираю на GCC без параметров. Вечером - предоставлю больше сведений.

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

Не может этого быть. Маска + сравнение... Скорее всего тормозит printf даже при печати в /dev/null
ведь ему надо сделать десятичное форматирование cnt и еще ряд каких-то блокировок и фиксаций в разделяемый
объект стандартного вывода.

Для C(6, 100) эта строчка выполняется 1.2 миллиарда раз. Т.е. (cnt & 0x3FFFFFF) == 0 выполняется со скоростью примерно 10 миллиардов раз в секунду.

Ну смотри... этот код на самом деле не должен срабатывать точно-точно каждые 2 мильярда итераций.
Это-ж для статистики? Тоесть я могу сюда поставить любую константу кратную числу вложенных
итераций от верхних циклов. Тогда эту проверку можно вообще убрать а printf просто вынести на 4-5
уровней циклов выше.

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
void all_combinations_6(int n) {
	printf("C(6, %d)\n", n);
	int cnt = 0;
	for (int i1 = 1; i1 <= n - 5; i1++)
		for (int i2 = i1 + 1; i2 <= n - 4; i2++)
			for (int i3 = i2 + 1; i3 <= n - 3; i3++) {
                                printf("Total: %d\r", cnt);
				for (int i4 = i3 + 1; i4 <= n - 2; i4++)
					for (int i5 = i4 + 1; i5 <= n - 1; i5++)
						for (int i6 = i5 + 1; i6 <= n; i6++)
						{
							//printf("%d %d %d %d %d %d\n", i1, i2, i3, i4, i5, i6);
							cnt++;
							// if ((cnt & 0x3FFFFFF) == 0) printf("Total: %d\r", cnt);
						}
	printf("Total: %d\n", cnt);
        ....... тут добавить скобочек....
}
...
Рейтинг: 0 / 0
Генерация сочетаний из N по K
    #40038677
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dima T
mayton
пропущено...

Ахахах!

Шаблонам же можно кучу однотипных функций компилировать, а мы чем хуже. Можно генератор кода написать

Кодогенерация для С++ в рантайме? .... Хм... эту тему надо вообще толкнуть отдельным топиком.

Насколько я помню тут ключевой вопрос - безопасность. В рантайме ты должен сгенерить неподписанную
никем *.dll -ку и динамически вызвать ее из главной процедуры. Антивирус сойдет с ума.

Это то что легко делается в языках типа JScript/Python/Node/Lisp через eval и то что почти
неизведанно как Антарктида в С++.

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

Для C(6, 100) эта строчка выполняется 1.2 миллиарда раз. Т.е. (cnt & 0x3FFFFFF) == 0 выполняется со скоростью примерно 10 миллиардов раз в секунду.

Ну смотри... этот код на самом деле не должен срабатывать точно-точно каждые 2 мильярда итераций.
Это-ж для статистики? Тоесть я могу сюда поставить любую константу кратную числу вложенных
итераций от верхних циклов. Тогда эту проверку можно вообще убрать а printf просто вынести на 4-5
уровней циклов выше.

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
void all_combinations_6(int n) {
	printf("C(6, %d)\n", n);
	int cnt = 0;
	for (int i1 = 1; i1 <= n - 5; i1++)
		for (int i2 = i1 + 1; i2 <= n - 4; i2++)
			for (int i3 = i2 + 1; i3 <= n - 3; i3++) {
                                printf("Total: %d\r", cnt);
				for (int i4 = i3 + 1; i4 <= n - 2; i4++)
					for (int i5 = i4 + 1; i5 <= n - 1; i5++)
						for (int i6 = i5 + 1; i6 <= n; i6++)
						{
							//printf("%d %d %d %d %d %d\n", i1, i2, i3, i4, i5, i6);
							cnt++;
							// if ((cnt & 0x3FFFFFF) == 0) printf("Total: %d\r", cnt);
						}
	printf("Total: %d\n", cnt);
        ....... тут добавить скобочек....
}


Не, так нельзя. Если ты закаментишь красное, то оптимизатор выкинет все циклы после твоего printf(). Я сначала без этой строчки написал, время работы 50 мс выдало.

Пусть будет, 1% времени на него расходуется.
Как выше писали: все-равно в реале вместо cnt++ внутри будет какое-то сохранение комбинации, а это на порядки дольше времени займет.
...
Рейтинг: 0 / 0
Генерация сочетаний из N по K
    #40038688
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
mayton
Насколько я помню тут ключевой вопрос - безопасность. В рантайме ты должен сгенерить неподписанную
никем *.dll -ку и динамически вызвать ее из главной процедуры. Антивирус сойдет с ума.

Думаю именно тут будет затык. Может еще админ права поотбирать.

Вообще я немного в другую сторону думал. Если известны часто используемые значения N, то для них прописать, а остальным универсальную запускать.
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
void all_combinations(int k, int n) {
   switch(k) {
     case 4:
       all_combinations_4(n);
       break;

     case 5:
       all_combinations_5(n);
       break;

...

     default:
       all_combinations_universal(k, n);
   }
}


Взять ту же задачу милторга, я так понимаю у него вектора были фиксированного размера, т.е. известного на момент компиляции.
...
Рейтинг: 0 / 0
25 сообщений из 174, страница 2 из 7
Форумы / Программирование [игнор отключен] [закрыт для гостей] / Генерация сочетаний из N по K
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


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