powered by simpleCommunicator - 2.0.59     © 2025 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Программирование [игнор отключен] [закрыт для гостей] / Как решить задачу по комбинаторике?
25 сообщений из 450, страница 5 из 18
Как решить задачу по комбинаторике?
    #39765027
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Я чем больше смотрю на эту задачу тем больше убеждаюсь что у нее нет аналитического решения.
А все наши прогнозы - просто маленькие предсказания на тему как уйти от факториала.
...
Рейтинг: 0 / 0
Как решить задачу по комбинаторике?
    #39765041
Gennadiy Usov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
maytonЯ чем больше смотрю на эту задачу тем больше убеждаюсь что у нее нет аналитического решения.
А все наши прогнозы - просто маленькие предсказания на тему как уйти от факториала.Предпочитаете не замечать аналитику 21794052 и 21793947 ?
...
Рейтинг: 0 / 0
Как решить задачу по комбинаторике?
    #39765050
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Решил. Исходник и ответВыкинуть надо число 10

Код: 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.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
138.
139.
140.
141.
142.
143.
#include <cstdio>
#include <algorithm>

// Копирование сортированного массива с пропуском заданных значений skipX (в порядке возрастания)
void copy_arr(const int* source, size_t size, int* dest, int skip0, int skip1 = 99, int skip2 = 99, int skip3 = 99, int skip4 = 99, int skip5 = 99) {
	const int *end = source + size;
	while (source < end && *source < skip0) *dest++ = *source++;
	source++;
	while (source < end && *source < skip1) *dest++ = *source++;
	source++;
	while (source < end && *source < skip2) *dest++ = *source++;
	source++;
	while (source < end && *source < skip3) *dest++ = *source++;
	source++;
	while (source < end && *source < skip4) *dest++ = *source++;
	source++;
	while (source < end && *source < skip5) *dest++ = *source++;
}

// Следующая комбинация элементов массива. false - больше нет
bool next_combination(size_t *idx, size_t size, size_t max) {
	for (size_t i = 0; i != size; i++) {
		idx[i]++;
		if (i + 1 == size) { // Последний
			if (idx[i] == max) {
				idx[i - 1] = i - 1;
				idx[i] = i;
				return false;
			}
		} else { // Не последний
			if (idx[i] == idx[i + 1]) {
				idx[i] = i;
			} else {
				break;
			}
		}
	}
	return true;
}

// Проверка что массив отсортирован
bool is_sort(int* arr, size_t size) {
	for (size_t i = 1; i != size; i++) {
		if (arr[i] <= arr[i - 1]) return false;
	}
	return true;
}

int count = 0;

void start(int center, int sum, int lost) {
	int num17[17] = { 1, 2, 3, 4, 5, 7, 8, 9, 10, 11, 13, 14, 15, 16, 17, 19, 20 };
	int num15[15]; // Массив без center и lost
	if (center < lost) {
		copy_arr(num17, 17, num15, center, lost);
	} else {
		copy_arr(num17, 17, num15, lost, center);
	}
	// Заполнение среднего круга по 4 из 15
	size_t ic[4] = {0, 1, 2, 3}; // Индексы выбранных элементов
	do { // Перебор по 4 из 15
		if (sum == 18 + 6 + num15[ic[0]] + num15[ic[1]] + num15[ic[2]] + num15[ic[3]]) {
			int num11[11];
			copy_arr(num15, 15, num11, num15[ic[0]], num15[ic[1]], num15[ic[2]], num15[ic[3]]);
			// Заполнение внешнего круга по 5 из 11
			size_t ie[5] = { 0, 1, 2, 3, 4}; // Индексы выбранных элементов
			do {
				if (sum == 12 + num11[ie[0]] + num11[ie[1]] + num11[ie[2]] + num11[ie[3]] + num11[ie[4]]) {
					int num_i[6]; // Внутреннее кольцо
					copy_arr(num11, 11, num_i, num11[ie[0]], num11[ie[1]], num11[ie[2]], num11[ie[3]], num11[ie[4]]);
					// Проверка суммы внутреннего кольца
					if (sum != num_i[0] + num_i[1] + num_i[2] + num_i[3] + num_i[4] + num_i[5]) {
						printf("!!! ERROR sum !!!\n");
						return;
					}
					if (!is_sort(num_i, 6)) {
						printf("!!! ERROR sort num_i !!!\n");
						return;
					}
					// Проверка диаметров
					// Нумерация х в соответствии с https://www.sql.ru/forum/actualutils.aspx?action=gotomsg&tid=1308126&msg=21793805
					int *x2 = &num_i[0], *x3 = &num_i[1], *x4 = &num_i[2], *x5 = &num_i[3], *x6 = &num_i[4], *x7 = &num_i[5];
					int num_e[5]; // Внешнее кольцо
					int *x12 = &num_e[0], *x13 = &num_e[1], *x14 = &num_e[2], *x15 = &num_e[3], *x16 = &num_e[4];
					for (size_t i = 0; i != 5; i++) num_e[i] = num11[ie[i]];
					if (!is_sort(num_e, 5)) {
						printf("!!! ERROR sort num_e !!!\n");
						return;
					}
					int num_c[4]; // Среднее кольцо
					int *x8 = &num_c[0], *x9 = &num_c[1], *x10 = &num_c[2], *x11 = &num_c[3];
					for (size_t i = 0; i != 4; i++) num_c[i] = num15[ic[i]];
					if (!is_sort(num_c, 4)) {
						printf("!!! ERROR sort num_c !!!\n");
						return;
					}

					int *x1 = &center;
					do { // Вращение внутреннего кольца
						do { // Вращение внешнего кольца
							// Горизонтальный
							if (sum == 12 + *x2 + *x1 + *x5 + *x15) {
								// Справа налево
								if (sum == *x14 + *x4 + *x1 + *x7 + *x12) {
									// Слева направо
									if (sum == *x13 + *x3 + *x1 + *x6 + *x16) {
										do { // Вращение среднего кольца
											// Шесть кругов
											if (sum == 12 + *x9 + *x3 + *x6 + *x11 + *x12) {
												if (sum == 12 + *x13 + *x10 + *x4 + *x7 + *x8) {
													if (sum == *x13 + *x14 + 18 + *x5 + *x2 + *x9) {
														if (sum == *x14 + *x15 + 6 + *x6 + *x3 + *x10) {
															if (sum == *x15 + *x16 + *x11 + *x7 + *x4 + 18) {
																if (sum == *x16 + *x12 + *x8 + *x2 + *x5 + 6) {
																	count++;
																	// Тут можно вывести правильное решение
																}
															}
														}
													}
												}
											}
										} while (std::next_permutation(num_c, num_c + 4));
									}
								}
							}
						} while (std::next_permutation(num_e, num_e + 5));
					} while (std::next_permutation(num_i, num_i + 6));
					
				}
			} while (next_combination(ie, 5, 11));
		}
	} while (next_combination(ic, 4, 15));
}

int main(int argc, char** argv[])
{
	start(19, 57, 20);
	printf("count %d\n", count);
	start(20, 60, 10);
	printf("count %d\n", count);
	return 0;
}


Результат:
Код: plaintext
1.
count 0
count 16

Кому надо 16 правильных расстановок - я пометил место где их выводить.
...
Рейтинг: 0 / 0
Как решить задачу по комбинаторике?
    #39765052
Gennadiy Usov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Dima T
Решил. Исходник и ответВыкинуть надо число 10

Код: 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.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
138.
139.
140.
141.
142.
143.
#include <cstdio>
#include <algorithm>

// Копирование сортированного массива с пропуском заданных значений skipX (в порядке возрастания)
void copy_arr(const int* source, size_t size, int* dest, int skip0, int skip1 = 99, int skip2 = 99, int skip3 = 99, int skip4 = 99, int skip5 = 99) {
	const int *end = source + size;
	while (source < end && *source < skip0) *dest++ = *source++;
	source++;
	while (source < end && *source < skip1) *dest++ = *source++;
	source++;
	while (source < end && *source < skip2) *dest++ = *source++;
	source++;
	while (source < end && *source < skip3) *dest++ = *source++;
	source++;
	while (source < end && *source < skip4) *dest++ = *source++;
	source++;
	while (source < end && *source < skip5) *dest++ = *source++;
}

// Следующая комбинация элементов массива. false - больше нет
bool next_combination(size_t *idx, size_t size, size_t max) {
	for (size_t i = 0; i != size; i++) {
		idx[i]++;
		if (i + 1 == size) { // Последний
			if (idx[i] == max) {
				idx[i - 1] = i - 1;
				idx[i] = i;
				return false;
			}
		} else { // Не последний
			if (idx[i] == idx[i + 1]) {
				idx[i] = i;
			} else {
				break;
			}
		}
	}
	return true;
}

// Проверка что массив отсортирован
bool is_sort(int* arr, size_t size) {
	for (size_t i = 1; i != size; i++) {
		if (arr[i] <= arr[i - 1]) return false;
	}
	return true;
}

int count = 0;

void start(int center, int sum, int lost) {
	int num17[17] = { 1, 2, 3, 4, 5, 7, 8, 9, 10, 11, 13, 14, 15, 16, 17, 19, 20 };
	int num15[15]; // Массив без center и lost
	if (center < lost) {
		copy_arr(num17, 17, num15, center, lost);
	} else {
		copy_arr(num17, 17, num15, lost, center);
	}
	// Заполнение среднего круга по 4 из 15
	size_t ic[4] = {0, 1, 2, 3}; // Индексы выбранных элементов
	do { // Перебор по 4 из 15
		if (sum == 18 + 6 + num15[ic[0]] + num15[ic[1]] + num15[ic[2]] + num15[ic[3]]) {
			int num11[11];
			copy_arr(num15, 15, num11, num15[ic[0]], num15[ic[1]], num15[ic[2]], num15[ic[3]]);
			// Заполнение внешнего круга по 5 из 11
			size_t ie[5] = { 0, 1, 2, 3, 4}; // Индексы выбранных элементов
			do {
				if (sum == 12 + num11[ie[0]] + num11[ie[1]] + num11[ie[2]] + num11[ie[3]] + num11[ie[4]]) {
					int num_i[6]; // Внутреннее кольцо
					copy_arr(num11, 11, num_i, num11[ie[0]], num11[ie[1]], num11[ie[2]], num11[ie[3]], num11[ie[4]]);
					// Проверка суммы внутреннего кольца
					if (sum != num_i[0] + num_i[1] + num_i[2] + num_i[3] + num_i[4] + num_i[5]) {
						printf("!!! ERROR sum !!!\n");
						return;
					}
					if (!is_sort(num_i, 6)) {
						printf("!!! ERROR sort num_i !!!\n");
						return;
					}
					// Проверка диаметров
					// Нумерация х в соответствии с https://www.sql.ru/forum/actualutils.aspx?action=gotomsg&tid=1308126&msg=21793805
					int *x2 = &num_i[0], *x3 = &num_i[1], *x4 = &num_i[2], *x5 = &num_i[3], *x6 = &num_i[4], *x7 = &num_i[5];
					int num_e[5]; // Внешнее кольцо
					int *x12 = &num_e[0], *x13 = &num_e[1], *x14 = &num_e[2], *x15 = &num_e[3], *x16 = &num_e[4];
					for (size_t i = 0; i != 5; i++) num_e[i] = num11[ie[i]];
					if (!is_sort(num_e, 5)) {
						printf("!!! ERROR sort num_e !!!\n");
						return;
					}
					int num_c[4]; // Среднее кольцо
					int *x8 = &num_c[0], *x9 = &num_c[1], *x10 = &num_c[2], *x11 = &num_c[3];
					for (size_t i = 0; i != 4; i++) num_c[i] = num15[ic[i]];
					if (!is_sort(num_c, 4)) {
						printf("!!! ERROR sort num_c !!!\n");
						return;
					}

					int *x1 = &center;
					do { // Вращение внутреннего кольца
						do { // Вращение внешнего кольца
							// Горизонтальный
							if (sum == 12 + *x2 + *x1 + *x5 + *x15) {
								// Справа налево
								if (sum == *x14 + *x4 + *x1 + *x7 + *x12) {
									// Слева направо
									if (sum == *x13 + *x3 + *x1 + *x6 + *x16) {
										do { // Вращение среднего кольца
											// Шесть кругов
											if (sum == 12 + *x9 + *x3 + *x6 + *x11 + *x12) {
												if (sum == 12 + *x13 + *x10 + *x4 + *x7 + *x8) {
													if (sum == *x13 + *x14 + 18 + *x5 + *x2 + *x9) {
														if (sum == *x14 + *x15 + 6 + *x6 + *x3 + *x10) {
															if (sum == *x15 + *x16 + *x11 + *x7 + *x4 + 18) {
																if (sum == *x16 + *x12 + *x8 + *x2 + *x5 + 6) {
																	count++;
																	// Тут можно вывести правильное решение
																}
															}
														}
													}
												}
											}
										} while (std::next_permutation(num_c, num_c + 4));
									}
								}
							}
						} while (std::next_permutation(num_e, num_e + 5));
					} while (std::next_permutation(num_i, num_i + 6));
					
				}
			} while (next_combination(ie, 5, 11));
		}
	} while (next_combination(ic, 4, 15));
}

int main(int argc, char** argv[])
{
	start(19, 57, 20);
	printf("count %d\n", count);
	start(20, 60, 10);
	printf("count %d\n", count);
	return 0;
}


Результат:
Код: plaintext
1.
count 0
count 16

Кому надо 16 правильных расстановок - я пометил место где их выводить.
1) А ответов нет. Трудно их показать?

2) Почему только 10? Причина.

3) Полный перебор не интересно. Компьютер помогает.
Лучше пошагово, аналитически, так как сам мыслишь.
...
Рейтинг: 0 / 0
Как решить задачу по комбинаторике?
    #39765059
alex55555
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
kealon(Ruslan)13 уравнений с 18 неизвестными сводится к диафантовому уравнению с 6 неизвестными

а это 17!/(17-6)! вариантов
Вообще я в прошлый раз поторопился. Здесь система линейных неравенств. В смысле помимо уравнений присутствуют ограничения вида Хn>0 && Xn<21. Плюс "диофантовость", то есть ограничение на решение в целых числах. А количество неизвестных зависит ещё и от количества сумм, то есть если наконец определиться, что считать суммой - три круга и девять диаметров или девять кргуов и три диаметра - тогда (для первого случая) добавляются три неизвестных суммы для кругов и условие вхождения меньших диаметров в большие (то есть дополнительные уравнения).

В общем нужно просто сесть и потратить часик времени на рисование всех возможных уравнений и ограничений, потом посчитать количество неизвестных и уравнений, ну и используя ограничение на целостность числа совместно с устранением ряда неизвестных за счёт их выражения из уравнений системы, решить несколько получившихся диофантовых уравнений (штуки 4 всего).

Но я чувствую, народ мотивирован и найдёт эвристическое решение без перебора и уравнений, поэтому общий подход уже не столь интересен...
...
Рейтинг: 0 / 0
Как решить задачу по комбинаторике?
    #39765062
kealon(Ruslan)
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
alex55555,

21793795

kealon(Ruslan)13 уравнений: 9 кругов, 3 диагонали, 1 уравнение баланса
18 неизвестных: x1..x17 и S

единичность и принадлежность к диапазону я не знаю как подсчитать
...
Рейтинг: 0 / 0
Как решить задачу по комбинаторике?
    #39765064
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Gennadiy UsovmaytonЯ чем больше смотрю на эту задачу тем больше убеждаюсь что у нее нет аналитического решения.
А все наши прогнозы - просто маленькие предсказания на тему как уйти от факториала.Предпочитаете не замечать аналитику 21794052 и 21793947 ?
Аналитического решения не существует для комбинаторных задач в общем понимании
этого слова. Сюда же 1000 ферзей.

Но создатели упростили нам это введя пограничные условия. 3 константы. И 1 исключение из списка целых.

Что вы будете делать если пограничных условий не будет?

Я в скобках напомню что мы находимся в форуме посвященном программированию и 99% респондентов
заинтересованы программировать задачу а не решать ее в уме.

Таковы реалии.
...
Рейтинг: 0 / 0
Как решить задачу по комбинаторике?
    #39765080
Gennadiy Usov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
maytonGennadiy UsovПредпочитаете не замечать аналитику 21794052 и 21793947 ?
Аналитического решения не существует для комбинаторных задач в общем понимании
этого слова. Сюда же 1000 ферзей.

Но создатели упростили нам это введя пограничные условия. 3 константы. И 1 исключение из списка целых.

Что вы будете делать если пограничных условий не будет?

Я в скобках напомню что мы находимся в форуме посвященном программированию и 99% респондентов
заинтересованы программировать задачу а не решать ее в уме.

Таковы реалии.Получается, что тупо поиск с возвратом, где перебираются все значения по всем окружностям и диагоналям.

А где ограничения, упрощения?
С целью уменьшения вариантов поиска?

Для показа этих упрощений не обязательна нужна программа.
...
Рейтинг: 0 / 0
Как решить задачу по комбинаторике?
    #39765094
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Gennadiy Usovmaytonпропущено...

Аналитического решения не существует для комбинаторных задач в общем понимании
этого слова. Сюда же 1000 ферзей.

Но создатели упростили нам это введя пограничные условия. 3 константы. И 1 исключение из списка целых.

Что вы будете делать если пограничных условий не будет?

Я в скобках напомню что мы находимся в форуме посвященном программированию и 99% респондентов
заинтересованы программировать задачу а не решать ее в уме.

Таковы реалии.Получается, что тупо поиск с возвратом, где перебираются все значения по всем окружностям и диагоналям.

А где ограничения, упрощения?
С целью уменьшения вариантов поиска?

Для показа этих упрощений не обязательна нужна программа.
Да. В данном форуме программа является доказательством.

Доказательством корректнсти программы является ее работа и ее результат.

Не просмотр глазами. И не умозрительные заключения.

Если дима привел программу. И она у нас заработает. И выдаст корректный результат.

То для всех присутствующих будет очевидно что она верна. Тот кто считает что она
не верна должен будет доказать обратное.

Чтобы проверить правильность формул. Необходимо всех присутствующих провести
через ДОКАЗАТЕЛЬСТВО этих формул.
...
Рейтинг: 0 / 0
Как решить задачу по комбинаторике?
    #39765109
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
По поводу упрощений. Просмотрите код Димы и внесите свои предложения по упрощениями.
...
Рейтинг: 0 / 0
Как решить задачу по комбинаторике?
    #39765116
Соколинский Борис
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Ради интереса забил задачу в Excel для проверки Solver-а. Он не оправдал оказанного ему высокого доверия, заклинило на нерешенном состоянии.
...
Рейтинг: 0 / 0
Как решить задачу по комбинаторике?
    #39765118
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
А как современный Excel работает? Интерпретатор байткода?
...
Рейтинг: 0 / 0
Как решить задачу по комбинаторике?
    #39765119
Соколинский Борис
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
mayton,
Там три алгоритма зашито. В нашем случае номинально только эволюционный подходит.
Я его раньше тестировал на одной олимпиадной задаче, справился.
...
Рейтинг: 0 / 0
Как решить задачу по комбинаторике?
    #39765129
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Нашел. Называется Microsoft P-Code

https://en.wikipedia.org/wiki/Microsoft_P-Code
...
Рейтинг: 0 / 0
Как решить задачу по комбинаторике?
    #39765135
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Я подумал некрасиво без заполнения клеток, могут не поверить, поэтому все 16 вариантов.
x1x2x3x4x5x6x7x8x9x10x11x12x13x14x15x16x1720234171915811161145791310202315171948111611457913102021941731581116114579131020219151734811161145791310204321519178111611457913102043171519281116114579131020419215317811161145791310204191715328111611457913102015324191781116114579131020153174192811161145791310201519243178111611457913102015191743281116114579131020173421915811161145791310201731521948111611457913102017194231581116114579131020171915234811161145791310
Расположение переменных
...
Рейтинг: 0 / 0
Как решить задачу по комбинаторике?
    #39765141
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Дима. А ты мог-бы выложить трассу для одного ответа где
видно как меняется масса окружностей и диаметров?
...
Рейтинг: 0 / 0
Как решить задачу по комбинаторике?
    #39765184
kealon(Ruslan)
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dima T,

занятно, вариативны только 6 переменных
...
Рейтинг: 0 / 0
Как решить задачу по комбинаторике?
    #39765187
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Хм. Ценное замечание. Меняются только цифры внутреннего круга.
...
Рейтинг: 0 / 0
Как решить задачу по комбинаторике?
    #39765195
Gennadiy Usov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Как оказалось, уравнения не проходят - одни тождества.

Следовательно - поиск с возвратом.

Исходные данные – два варианта для х17 и х1, известны 3 числа, сумма чисел для 9 последовательностей (окружности и диагонали)
То есть, известны 5 чисел из 20 чисел.
Осталось найти 15 чисел

Шаг 1. цикл по х2 и х5 (из 15 и 14 чисел - отобрано 7 чисел) – определяем х15 (не равно 7 числам)
всего 8 чисел (1-я диагональ)

Шаг 2. цикл по х12 и х16 (из 13 и 12 чисел - отобрано 10 чисел) - определяем х8 (не равно 10 числам)
всего 11 чисел(1-я внутренняя окружность)

Шаг 3. цикл по х13 (из 9 чисел - отобрано 12 чисел) – определяем х14 (не равно 12 числам)
всего 13 чисел (большая окружность)

Шаг 4. - определяем х9 (не равно 13 числам)
всего 14 чисел (2-я внутренняя окружность)

Шаг 5. цикл по х10 (из 6 чисел - отобрано 15 чисел) - определяем х11(не равно 15 числам)
всего 16 чисел.

Шаг 6. Далее проверки:
- сумма х3 и х6 сравниваем с (2-я диагональ) (2-я внутренняя окружность) (4-я внутренняя окружность)
- сумма х4 и х7 сравниваем с (3-я диагональ) (5-я внутренняя окружность) (6-я внутренняя окружность)
- суммы х3,х4,х6,х7 сравниваем с (внутренняя окружность)

Шаг 7. цикл по х7 (из 4 чисел - отобрано 17 чисел) – определяем х4 ( не равно 17 числам)
всего 18 чисел.

Шаг 8. цикл по х3 (из 2 чисел - отобрано 19 чисел) – определяем х5 ( равно последнему свободному числу)

Если при работе цикла не определяются свободные числа, то возврат на предыдущий шаг.

Можно усложнить алгоритм, когда ничего не известно
...
Рейтинг: 0 / 0
Как решить задачу по комбинаторике?
    #39765200
Gennadiy Usov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Забыл указать в исходных данных, что имеем 20 чисел от 1 до 20.

Тут следует вспомнить следующее сообщение:maytonGennadiy UsovСкорее тут будет метод поиска с возвратом:
ищем, суммируем, подходит или не подходит, если нет, то возвращаемся...Я не про это. Я знаю как решать эту задачу.
Я не знаю как описать входные данные красиво.

Представте что завтра граф будет другой. С большим числом вершин и другими условиями.
Сколько кода вам надо будет сломать?А если доработать схему по-шаговых действий 21794700 для случая, когда ничего не известно.

1) Вместо известных значений вводим переменные: х18(6), х19(12), х20(8).
И в тех объектах (окружность, диагональ), где эти переменные впервые появляются, добавляется цикл по этим переменным, аналогично остальным переменным.

2) Имеем массив произвольных 20 чисел. Определяем их сумму К.
Каждой переменной х... ставится в соответствие определенный элемент массива.

3) Строим внешний цикл по переменным х1 и х17, причем есть ограничение:
величина (К + х1 - х17) должна делиться на 3.
Тогда К1 = (К - х1 - х17)/3 будет являться суммой чисел в каждом объекте (окружность, диагональ).

А если совсем углубиться (ударение на втором у), то можно ещё ввести соотношения между объектами (окружность, диагональ).

А если и ...., то можно вообще рисовать произвольные картинки, только успевай выстраивать новые схемы, которые будут похожи на 21794700

Так что, вариантов обобщения и углубления много.
...
Рейтинг: 0 / 0
Как решить задачу по комбинаторике?
    #39765204
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
maytonДима. А ты мог-бы выложить трассу для одного ответа где
видно как меняется масса окружностей и диаметров?
Это обычный перебор, пропускаются варианты с неправильной суммой. Т.е. Наполнили средний круг, сумма не совпала, следующий средний, совпала, наполнили внешний круг, сумма не совпала следующий внешний и т.д.

Вот тот же исходник с выводом значения узлов. Его результат скопипастил сюда 21794557
Код: 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.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
138.
139.
140.
141.
142.
143.
#include <cstdio>
#include <algorithm>

// Копирование сортированного массива с пропуском заданных значений skipX (в порядке возрастания)
void copy_arr(const int* source, size_t size, int* dest, int skip0, int skip1 = 99, int skip2 = 99, int skip3 = 99, int skip4 = 99, int skip5 = 99) {
	const int *end = source + size;
	while (source < end && *source < skip0) *dest++ = *source++;
	source++;
	while (source < end && *source < skip1) *dest++ = *source++;
	source++;
	while (source < end && *source < skip2) *dest++ = *source++;
	source++;
	while (source < end && *source < skip3) *dest++ = *source++;
	source++;
	while (source < end && *source < skip4) *dest++ = *source++;
	source++;
	while (source < end && *source < skip5) *dest++ = *source++;
}

// Следующая комбинация элементов массива. false - больше нет
bool next_combination(size_t *idx, size_t size, size_t max) {
	for (size_t i = 0; i != size; i++) {
		idx[i]++;
		if (i + 1 == size) { // Последний
			if (idx[i] == max) {
				idx[i - 1] = i - 1;
				idx[i] = i;
				return false;
			}
		} else { // Не последний
			if (idx[i] == idx[i + 1]) {
				idx[i] = i;
			} else {
				break;
			}
		}
	}
	return true;
}

// Проверка что массив отсортирован
bool is_sort(int* arr, size_t size) {
	for (size_t i = 1; i != size; i++) {
		if (arr[i] <= arr[i - 1]) return false;
	}
	return true;
}

int count = 0;

void start(int center, int sum, int lost) {
	int num17[17] = { 1, 2, 3, 4, 5, 7, 8, 9, 10, 11, 13, 14, 15, 16, 17, 19, 20 };
	int num15[15]; // Массив без center и lost
	if (center < lost) {
		copy_arr(num17, 17, num15, center, lost);
	} else {
		copy_arr(num17, 17, num15, lost, center);
	}
	// Заполнение среднего круга по 4 из 15
	size_t ic[4] = {0, 1, 2, 3}; // Индексы выбранных элементов
	do { // Перебор по 4 из 15
		if (sum == 18 + 6 + num15[ic[0]] + num15[ic[1]] + num15[ic[2]] + num15[ic[3]]) {
			int num11[11];
			copy_arr(num15, 15, num11, num15[ic[0]], num15[ic[1]], num15[ic[2]], num15[ic[3]]);
			// Заполнение внешнего круга по 5 из 11
			size_t ie[5] = { 0, 1, 2, 3, 4}; // Индексы выбранных элементов
			do {
				if (sum == 12 + num11[ie[0]] + num11[ie[1]] + num11[ie[2]] + num11[ie[3]] + num11[ie[4]]) {
					int num_i[6]; // Внутреннее кольцо
					copy_arr(num11, 11, num_i, num11[ie[0]], num11[ie[1]], num11[ie[2]], num11[ie[3]], num11[ie[4]]);
					// Проверка суммы внутреннего кольца
					if (sum != num_i[0] + num_i[1] + num_i[2] + num_i[3] + num_i[4] + num_i[5]) {
						printf("!!! ERROR sum !!!\n");
						return;
					}
					if (!is_sort(num_i, 6)) {
						printf("!!! ERROR sort num_i !!!\n");
						return;
					}
					// Проверка диаметров
					// Нумерация х в соответствии с https://www.sql.ru/forum/actualutils.aspx?action=gotomsg&tid=1308126&msg=21793805
					int *x2 = &num_i[0], *x3 = &num_i[1], *x4 = &num_i[2], *x5 = &num_i[3], *x6 = &num_i[4], *x7 = &num_i[5];
					int num_e[5]; // Внешнее кольцо
					int *x12 = &num_e[0], *x13 = &num_e[1], *x14 = &num_e[2], *x15 = &num_e[3], *x16 = &num_e[4];
					for (size_t i = 0; i != 5; i++) num_e[i] = num11[ie[i]];
					if (!is_sort(num_e, 5)) {
						printf("!!! ERROR sort num_e !!!\n");
						return;
					}
					int num_c[4]; // Среднее кольцо
					int *x8 = &num_c[0], *x9 = &num_c[1], *x10 = &num_c[2], *x11 = &num_c[3];
					for (size_t i = 0; i != 4; i++) num_c[i] = num15[ic[i]];
					if (!is_sort(num_c, 4)) {
						printf("!!! ERROR sort num_c !!!\n");
						return;
					}

					int *x1 = &center;
					do { // Вращение внутреннего кольца
						do { // Вращение внешнего кольца
							// Горизонтальный
							if (sum == 12 + *x2 + *x1 + *x5 + *x15) {
								// Справа налево
								if (sum == *x14 + *x4 + *x1 + *x7 + *x12) {
									// Слева направо
									if (sum == *x13 + *x3 + *x1 + *x6 + *x16) {
										do { // Вращение среднего кольца
											// Шесть кругов
											if (sum == 12 + *x9 + *x3 + *x6 + *x11 + *x12) {
												if (sum == 12 + *x13 + *x10 + *x4 + *x7 + *x8) {
													if (sum == *x13 + *x14 + 18 + *x5 + *x2 + *x9) {
														if (sum == *x14 + *x15 + 6 + *x6 + *x3 + *x10) {
															if (sum == *x15 + *x16 + *x11 + *x7 + *x4 + 18) {
																if (sum == *x16 + *x12 + *x8 + *x2 + *x5 + 6) {
																	count++;
																	printf("%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d\n", *x1, *x2, *x3, *x4, *x5, *x6, *x7, *x8, *x9, *x10, *x11, *x12, *x13, *x14, *x15, *x16, lost);
																}
															}
														}
													}
												}
											}
										} while (std::next_permutation(num_c, num_c + 4));
									}
								}
							}
						} while (std::next_permutation(num_e, num_e + 5));
					} while (std::next_permutation(num_i, num_i + 6));
					
				}
			} while (next_combination(ie, 5, 11));
		}
	} while (next_combination(ic, 4, 15));
}

int main(int argc, char** argv[])
{
	start(19, 57, 20);
	printf("count %d\n", count);
	start(20, 60, 10);
	printf("count %d\n", count);
	return 0;
}

...
Рейтинг: 0 / 0
Как решить задачу по комбинаторике?
    #39765234
Gennadiy Usov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Можно ещё упростить схему алгоритма, при этом убираем один цикл

Исходные данные – два варианта для х17 и х1, известны 3 числа, сумма чисел для 9 последовательностей (окружности и диагонали)
То есть, известны 5 чисел из 20 чисел.
Осталось найти 15 чисел

Для начала введем 3 переменные:
а1 = х2 + х5
а2 = х3 + х6
а3 = х4 + х7

Шаг 1. цикл по х15 (из 15 чисел - отобрано 6 чисел) – определяем а1
всего 6 чисел (1-я диагональ)

Шаг 2. цикл по х12 и х16 (из 14 и 13 чисел - отобрано 8 чисел) - определяем х8 (не равно 8 числам)
всего 9 чисел(1-я внутренняя окружность)

Далее из (большая окружность) и из (внутренняя окружность) – определяем х9 (не равно 9 числам).
Всего 10 чисел.

Шаг 3. цикл по х10 (из 10 чисел - отобрано 11 чисел) - определяем х11(не равно 11 числам)
всего 12 чисел. (средняя окружность).

Далее определяем: а2, а3, х13, х14,

Шаг 4. Цикл по х2 в а1- определяем х5
Шаг 5. Цикл по х3 в а2 – определяем х6
Шаг 6. Цикл по х4 в а3 – определяем х7

Если при работе цикла не определяются свободные числа, то возврат на предыдущий шаг.
...
Рейтинг: 0 / 0
Как решить задачу по комбинаторике?
    #39765238
Соколинский Борис
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
maytonХм. Ценное замечание. Меняются только цифры внутреннего круга. По-моему, так быть не может, где-то ошибка при проверке условия - у двух триплетов сумма любой пары должна быть одинаковой. 6 условий и 6 переменных - единственное решение.
...
Рейтинг: 0 / 0
Как решить задачу по комбинаторике?
    #39765269
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dima TmaytonДима. А ты мог-бы выложить трассу для одного ответа где
видно как меняется масса окружностей и диаметров?
Это обычный перебор, пропускаются варианты с неправильной суммой. Т.е. Наполнили средний круг, сумма не совпала, следующий средний, совпала, наполнили внешний круг, сумма не совпала следующий внешний и т.д.

Вот тот же исходник с выводом значения узлов. Его результат скопипастил сюда 21794557
Код: 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.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
138.
139.
140.
141.
142.
143.
#include <cstdio>
#include <algorithm>

// Копирование сортированного массива с пропуском заданных значений skipX (в порядке возрастания)
void copy_arr(const int* source, size_t size, int* dest, int skip0, int skip1 = 99, int skip2 = 99, int skip3 = 99, int skip4 = 99, int skip5 = 99) {
	const int *end = source + size;
	while (source < end && *source < skip0) *dest++ = *source++;
	source++;
	while (source < end && *source < skip1) *dest++ = *source++;
	source++;
	while (source < end && *source < skip2) *dest++ = *source++;
	source++;
	while (source < end && *source < skip3) *dest++ = *source++;
	source++;
	while (source < end && *source < skip4) *dest++ = *source++;
	source++;
	while (source < end && *source < skip5) *dest++ = *source++;
}

// Следующая комбинация элементов массива. false - больше нет
bool next_combination(size_t *idx, size_t size, size_t max) {
	for (size_t i = 0; i != size; i++) {
		idx[i]++;
		if (i + 1 == size) { // Последний
			if (idx[i] == max) {
				idx[i - 1] = i - 1;
				idx[i] = i;
				return false;
			}
		} else { // Не последний
			if (idx[i] == idx[i + 1]) {
				idx[i] = i;
			} else {
				break;
			}
		}
	}
	return true;
}

// Проверка что массив отсортирован
bool is_sort(int* arr, size_t size) {
	for (size_t i = 1; i != size; i++) {
		if (arr[i] <= arr[i - 1]) return false;
	}
	return true;
}

int count = 0;

void start(int center, int sum, int lost) {
	int num17[17] = { 1, 2, 3, 4, 5, 7, 8, 9, 10, 11, 13, 14, 15, 16, 17, 19, 20 };
	int num15[15]; // Массив без center и lost
	if (center < lost) {
		copy_arr(num17, 17, num15, center, lost);
	} else {
		copy_arr(num17, 17, num15, lost, center);
	}
	// Заполнение среднего круга по 4 из 15
	size_t ic[4] = {0, 1, 2, 3}; // Индексы выбранных элементов
	do { // Перебор по 4 из 15
		if (sum == 18 + 6 + num15[ic[0]] + num15[ic[1]] + num15[ic[2]] + num15[ic[3]]) {
			int num11[11];
			copy_arr(num15, 15, num11, num15[ic[0]], num15[ic[1]], num15[ic[2]], num15[ic[3]]);
			// Заполнение внешнего круга по 5 из 11
			size_t ie[5] = { 0, 1, 2, 3, 4}; // Индексы выбранных элементов
			do {
				if (sum == 12 + num11[ie[0]] + num11[ie[1]] + num11[ie[2]] + num11[ie[3]] + num11[ie[4]]) {
					int num_i[6]; // Внутреннее кольцо
					copy_arr(num11, 11, num_i, num11[ie[0]], num11[ie[1]], num11[ie[2]], num11[ie[3]], num11[ie[4]]);
					// Проверка суммы внутреннего кольца
					if (sum != num_i[0] + num_i[1] + num_i[2] + num_i[3] + num_i[4] + num_i[5]) {
						printf("!!! ERROR sum !!!\n");
						return;
					}
					if (!is_sort(num_i, 6)) {
						printf("!!! ERROR sort num_i !!!\n");
						return;
					}
					// Проверка диаметров
					// Нумерация х в соответствии с https://www.sql.ru/forum/actualutils.aspx?action=gotomsg&tid=1308126&msg=21793805
					int *x2 = &num_i[0], *x3 = &num_i[1], *x4 = &num_i[2], *x5 = &num_i[3], *x6 = &num_i[4], *x7 = &num_i[5];
					int num_e[5]; // Внешнее кольцо
					int *x12 = &num_e[0], *x13 = &num_e[1], *x14 = &num_e[2], *x15 = &num_e[3], *x16 = &num_e[4];
					for (size_t i = 0; i != 5; i++) num_e[i] = num11[ie[i]];
					if (!is_sort(num_e, 5)) {
						printf("!!! ERROR sort num_e !!!\n");
						return;
					}
					int num_c[4]; // Среднее кольцо
					int *x8 = &num_c[0], *x9 = &num_c[1], *x10 = &num_c[2], *x11 = &num_c[3];
					for (size_t i = 0; i != 4; i++) num_c[i] = num15[ic[i]];
					if (!is_sort(num_c, 4)) {
						printf("!!! ERROR sort num_c !!!\n");
						return;
					}

					int *x1 = &center;
					do { // Вращение внутреннего кольца
						do { // Вращение внешнего кольца
							// Горизонтальный
							if (sum == 12 + *x2 + *x1 + *x5 + *x15) {
								// Справа налево
								if (sum == *x14 + *x4 + *x1 + *x7 + *x12) {
									// Слева направо
									if (sum == *x13 + *x3 + *x1 + *x6 + *x16) {
										do { // Вращение среднего кольца
											// Шесть кругов
											if (sum == 12 + *x9 + *x3 + *x6 + *x11 + *x12) {
												if (sum == 12 + *x13 + *x10 + *x4 + *x7 + *x8) {
													if (sum == *x13 + *x14 + 18 + *x5 + *x2 + *x9) {
														if (sum == *x14 + *x15 + 6 + *x6 + *x3 + *x10) {
															if (sum == *x15 + *x16 + *x11 + *x7 + *x4 + 18) {
																if (sum == *x16 + *x12 + *x8 + *x2 + *x5 + 6) {
																	count++;
																	printf("%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d\n", *x1, *x2, *x3, *x4, *x5, *x6, *x7, *x8, *x9, *x10, *x11, *x12, *x13, *x14, *x15, *x16, lost);
																}
															}
														}
													}
												}
											}
										} while (std::next_permutation(num_c, num_c + 4));
									}
								}
							}
						} while (std::next_permutation(num_e, num_e + 5));
					} while (std::next_permutation(num_i, num_i + 6));
					
				}
			} while (next_combination(ie, 5, 11));
		}
	} while (next_combination(ic, 4, 15));
}

int main(int argc, char** argv[])
{
	start(19, 57, 20);
	printf("count %d\n", count);
	start(20, 60, 10);
	printf("count %d\n", count);
	return 0;
}


Ты уже опубликовал это где-то в гитхабе? Я хотел сделать несколько changes.
...
Рейтинг: 0 / 0
Как решить задачу по комбинаторике?
    #39765324
alex55555
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
maytonДоказательством корректнсти программы является ее работа и ее результат.
Но программисты же получают не просто результат, а оптимальный результат. Так вот по оптимальности решения полным перебором возможны большие вопросы.
...
Рейтинг: 0 / 0
25 сообщений из 450, страница 5 из 18
Форумы / Программирование [игнор отключен] [закрыт для гостей] / Как решить задачу по комбинаторике?
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


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