Гость
Целевая тема:
Создать новую тему:
Автор:
Форумы / C++ [игнор отключен] [закрыт для гостей] / Сочетания. Реализация. Вопросы и предложения / 14 сообщений из 14, страница 1 из 1
28.11.2014, 06:40
    #38818967
SashaMercury
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сочетания. Реализация. Вопросы и предложения
Здравствуйте.
Решил создать новую тему, ибо мне кажется данную задачу можно решить разными способами, и акцент в данном случае не идёт на длинную арифметику. Проблема была в том, что мы хотели сократить знаменатель к единице. Если администрация считает что не стоит создавать новый топик, то не возражаю чтобы, его закрыли.
То что требуется я реализовал сегодня.

Вспомогательные моменты.



Код: 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.
struct Number
{
	int num;
	int num2;
	int count;
	int* multipliers;
};

struct Number* initializeNumber(int a)
{
	struct Number* n = (struct Number*)malloc(sizeof(struct Number));
	n->num = a;
	n->num2 = a;
	n->count = 0;
	n->multipliers = NULL;
}

int viewNumber(struct Number* a)
{
	printf("num= %i\n", a->num);
	printf("num2= %i\n", a->num2);
	printf("divisors:");
	for (int i = 0; i < a->count; ++i)
	{
		printf("%i ", a->multipliers[i]);
	}
	printf("\n");
	return 0;
}

//assume a->num > 1
int factorization(struct Number* a)
{
	for (int i = 2; i<=a->num2; ++i) 
	{
		if (a->num2%i == 0)
		{
			a->count += 1;
			a->multipliers = (int*)realloc(a->multipliers, a->count*sizeof(int));
			a->multipliers[a->count - 1] = i;
			
			a->num2 /= i;
			factorization(a);
			break;
		}
	}
	return 0;
}



Как работает factorization. Например на входе 150, находит первый делитель слева 2, дальше рекурсивный запуск 75, находим 3, дальше рекурсивный запус 25, находим 5, дальше рекурсивный запуск 5, находим 5, рекурсивный запуск на 1, приводит к завершению. Вместо 150 получаем массив 2 3 5 5 .
Возможно данную функцию можно реализовать лучше, буду рад предложениям.

Вы наверное догадались зачем нужна эта функция. Фиксируем элемент знаменателя, и пытаемся найти такой элемент числитель, что a%b==0,если такой элемент не найден, то фиксированный элемент знаменателя раскладываем на простейшие и расширяем массив знаменателя . Вместо 150 у нас появится 4 числа 2 3 5 5 . Ниже код


Код: 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.
//Сочетания
char* la_combination(unsigned n, unsigned m)
{
	m = (n - m > m) ? m : n-m;
	int* up = (int*)malloc(sizeof(int)*m);//числитель
	int* down = (int*)malloc(sizeof(int)*m);//знаменатель

	for (int i = 1; i <= m; ++i)
	{
		*(up + m - i) = n - m + i;
		*(down + m - i) = i;
	}
#ifdef DEBUG
	for (int i = 0; i < m; ++i)
		printf("%i ", up[i]);
	printf("\n");
	for (int i = 0; i < m; ++i)
		printf("%i ", down[i]);
	printf("\n");
#endif

	int len_down = m;
	for (int i = 0; i < len_down; ++i)//1 проход по знаменателю, длина знаменателя меняется
	{
		if (down[i] != 1)
		{
			int j = 0;
			for (j = 0; j < m; ++j)//проход по числителю
			{
				if (!(up[j] % down[i]))
				{
					up[j] /= down[i];
					down[i] = 1;
					break;
				}
			}
			if (j == m && down[i]!=1) //если перебрали все элементы числителя, а фиксированный элемент знаменателя не сократили
			{
				struct Number* n = initializeNumber(down[i]);
				factorization(n); //раскладываю число на множители
				down[i] = 1;
				len_down += n->count;
				down = (int*)realloc(down, sizeof(int)*len_down);
				for (int i = 0; i < n->count; ++i)
				{
					down[len_down - n->count + i] = n->multipliers[i];
				}
				free(n->multipliers);
				free(n);
			}
		}
	}
#ifdef DEBUG
	for (int i = 0; i < m; ++i)
		printf("%i ", up[i]);
	printf("\n");
	for (int i = 0; i < len_down; ++i)
		printf("%i ", down[i]);
	printf("\n");
#endif
	char* res="1";
	char* t = (char*)malloc(10);
	for (int i = 0; i < m; ++i)
	{
		sprintf(t, "%d", up[i]);
		res = la_multiplication(res, t);
	}
	free(t);
	return res;
}



На функцию la_multiplication(res, t) можно не обращать внимание (но если нужна она реализована в соседнем топе), это сложение двух строк.


Мне интересно как вы бы решили аналогичную задачу, ну и возможно у кого-то есть замечания по рефакторингу кода, оптимизации алгоритмов, и конечно-же организации данных. (Может стоит создать статическую переменную под длину массива, и не создавать структуру, например)


PS
Вчера с трудом заснул и снились кошмары(из-за того что меня одолевали сомнения по тернарному оператору). Всё-таки не стоит использовать С++ только из-за расширенных возможностей тернарного оператора, сегодня изменил весь код в длинной арифметике на код Си.
...
Рейтинг: 0 / 0
28.11.2014, 13:11
    #38819429
SashaMercury
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сочетания. Реализация. Вопросы и предложения
Ребята, у меня сегодня был мой первый memory leak !!! Буквально 3 часа назад
...
Рейтинг: 0 / 0
28.11.2014, 13:15
    #38819436
SashaMercury
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сочетания. Реализация. Вопросы и предложения
В том смысле, что во время выполнения программы, появилось сообщение Memory leak, и выполнение программы остановилось Первый раз !
...
Рейтинг: 0 / 0
28.11.2014, 13:18
    #38819443
mayton
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сочетания. Реализация. Вопросы и предложения
Поздравляю. Прям как первый раз с женщиной....

А зачем тут рекурсия? Ну ... как-бы обычно ее используют там
где она удобна и наглядна. Деревья поиска там. Обход сложных
связных структур. А тут?
...
Рейтинг: 0 / 0
28.11.2014, 13:19
    #38819444
Anatoly Moskovsky
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сочетания. Реализация. Вопросы и предложения
SashaMercuryмой первый memory leak
Ага, щас. Далеко уже не первый. Мы просто жалели вас, не сообщали горькую правду :)

ЗЫ. Ничего страшного. У половины человечества ежемесячно бывает leak, и ничего, живут
...
Рейтинг: 0 / 0
28.11.2014, 13:22
    #38819455
SashaMercury
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сочетания. Реализация. Вопросы и предложения
Anatoly Moskovsky,

были раньше, но программа никогда не вылетала. А тут вылетела, и всё как надо, сообщение, мол у вас Memory leak, получите распишитесь !
...
Рейтинг: 0 / 0
28.11.2014, 13:25
    #38819468
SashaMercury
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сочетания. Реализация. Вопросы и предложения
mayton, спасибо :)
Ну а как тут без рекурсии ? Интуитивно она больше всего подходит. Я ведь не все делители числа ищу, а раскладываю число на минимальные множители (по факту на произведение простых чисел)
...
Рейтинг: 0 / 0
28.11.2014, 14:55
    #38819661
mayton
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сочетания. Реализация. Вопросы и предложения
Код: plaintext
1.
2.
3.
for (int i = 2; i<=a->num2; ++i) 
	{
		if (a->num2%i == 0)


О некоторых граблях с топорами.

Я расскажу для НЕ-рекурсивного варианта. То как я кодил факторизацию сам.
А ты уж подумай как эту инфу переварить.

Во первых. Не нужно делить на чётные. Нужно деление на 2
вынести из тела цикла. И захардкодить.

А цикл делать начиная от 3 и с шагом в 2.

И верхняя граница должна быть не до числа N которое ты проверяешь
а до SQRT(N). До квадратного корня.

Для квадратного корня не нужно брать вещественный кастинг.
Есть эффективный расчёт для целочисленного корня.
Есть оптимизации на базе производной от этого-же корня.

Уже расчитанные primes нужно складывать в кеш и использовать
их при разложении других неизвестных составных чисел.

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

Кеш можно сжимать исходя из свойств строгой монотонности
хранимых значений. Монотонность имеет характер очень
малого роста.

Последние факты я установил экспериментально.

И последнее. Задачи с primes и факторизациями в прикладных
применениях имеют разрядную сетку во много раз превышающую
int. В задачах критографии например оперируют с составным
числом порядка 128/256/512 бит.
...
Рейтинг: 0 / 0
28.11.2014, 15:10
    #38819687
SashaMercury
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сочетания. Реализация. Вопросы и предложения
Я расскажу для НЕ-рекурсивного варианта. То как я кодил факторизацию сам.
А ты уж подумай как эту инфу переварить.

maytonВо первых. Не нужно делить на чётные. Нужно деление на 2
вынести из тела цикла. И захардкодить.

А цикл делать начиная от 3 и с шагом в 2.


Почему ? Какой я результат получу для числа 4, например ?

maytonИ верхняя граница должна быть не до числа N которое ты проверяешь
а до SQRT(N). До квадратного корня.

Если цикл начинать с 2, то видимо так. А если с трёх, то для числа 22 например, корень между 4 и 5, таким образом делителей я не найду, хотя по идее должен был встретить 11(Если пропустить 2).
...
Рейтинг: 0 / 0
28.11.2014, 15:38
    #38819725
mayton
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сочетания. Реализация. Вопросы и предложения
Делителя 4 не должно существовать в принципе. Потому что делитель 4 это суть
дважды делитель по два.

Если ты где-то делишь на 4 значит скорее всего дефект в алгоритме факторизации.
Я говорю СКОРЕЕ ВСЕГО потому что не совсем представляю глубину твоего замысла.
С рекурсией и с глобальное переменной *Number. Мне не совсем ясен ее контракт.
Тоесть как с ней ПРАВИЛЬНО нужно работать.
...
Рейтинг: 0 / 0
28.11.2014, 15:40
    #38819730
mayton
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сочетания. Реализация. Вопросы и предложения
SashaMercuryЕсли цикл начинать с 2, то видимо так. А если с трёх, то для числа 22 например, корень между 4 и 5, таким образом делителей я не найду, хотя по идее должен был встретить 11(Если пропустить 2).
Для снятия дефекта корня просто прибавляй к результату единицу. (Округляй результат в сторону большего).
...
Рейтинг: 0 / 0
28.11.2014, 15:48
    #38819744
SashaMercury
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сочетания. Реализация. Вопросы и предложения
maytonДелителя 4 не должно существовать в принципе. Потому что делитель 4 это суть
дважды делитель по два.

Если ты где-то делишь на 4 значит скорее всего дефект в алгоритме факторизации.
Я говорю СКОРЕЕ ВСЕГО потому что не совсем представляю глубину твоего замысла.
С рекурсией и с глобальное переменной *Number. Мне не совсем ясен ее контракт.
Тоесть как с ней ПРАВИЛЬНО нужно работать.

Любое число можно разложить по степеням простых чисел.
Например на входе число 150. Находим минмальный делитель этого числа слева, начиная с 2, 150 делится на 2, потому первый делитель будет 2, теперь запускаем эту-же функцию, но с числом 75, проходим числа 2 3 , и находим 3, запускаем алгоритм для 25, находим 5, снова алгоритм для 5, снова находим 5, получили 1, выход.
т.о. 150=2*3*5^2
И если ни один из элементов числителя не делится на 150, то 150 я заменю на эти 4 числа..

Мне нужна структура чтобы храниться число элементов массива делителей(элементов разложения)
...
Рейтинг: 0 / 0
28.11.2014, 15:55
    #38819752
mayton
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сочетания. Реализация. Вопросы и предложения
Правильно.

150=2*3*5^2

Ты в этой формуле подтвердил мои слова. Все делители - простые числа. Некоторые - в степенях.

Но такой формы записи у тебя нету. Верно?

150=2*3*10

Потому что 10 - это как и 4 числа составные.
...
Рейтинг: 0 / 0
28.11.2014, 15:57
    #38819756
SashaMercury
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сочетания. Реализация. Вопросы и предложения
mayton,
нет конечно. Как я могу быть уверен что составное число найдёт себе пару сверху ? Зато насчёт простых чисел я всегда уверен
...
Рейтинг: 0 / 0
Форумы / C++ [игнор отключен] [закрыт для гостей] / Сочетания. Реализация. Вопросы и предложения / 14 сообщений из 14, страница 1 из 1
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


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