Гость
Целевая тема:
Создать новую тему:
Автор:
Форумы / Программирование [игнор отключен] [закрыт для гостей] / Вопрос о существовании более быстрого алгоритма. / 20 сообщений из 20, страница 1 из 1
22.09.2014, 08:40
    #38753215
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.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
#include <stdio.h>
#include <stdlib.h>
#include <math.h>

struct Point
{
	int x;
	int y;
};

//расстояние между двумя точками в D^2
long double get_distance_between_Points(struct Point* p1, struct Point* p2)
{
	long double dx = p1->x - p2->x;
	long double dy = p1->y - p2->y;
	return sqrt(dx*dx + dy*dy);
}

//вес графа. на входе адрес графа, количество точек, стартовая позиция
long double get_weight_graph(struct Point* p, int num, int s)
{
	long double res = 0;
	for (int i = 0; i < num; ++i)
	{
		res += get_distance_between_Points(p + i, p + s);
	}
	return res;
}

//Попытка провести интернет
bool try_connect_to_WEB(struct Point* p, int num, struct Point* center, long double money, int cast)
{
	long double res;
	int i = 0;
	do
	{
		res = get_weight_graph(p, num, i) + get_distance_between_Points(p + i, center);
		i += 1;
	} while (res*cast > money && i < num);
	return res*cast <= money;
}

int main(int argc, char** argv)
{
	FILE* in = fopen("input.txt", "r");
	if (!in)
	{
		printf("File 'input.txt' not found.\n");
		return 0;
	}
	
	//считываю данные
	int num, cast;
	long double money;
	fscanf(in, "%d %d %lf", &num, &cast, &money);
	struct Point* p = (struct Point*)malloc(sizeof(struct Point)*num);
	for (int i = 0; i < num; ++i)
	{
		fscanf(in, "%i %i", &p[i].x, &p[i].y);
	}
	struct Point center;
	fscanf(in, "%i %i", &center.x, &center.y);
	fclose(in);

	//расчёт
	FILE* out = fopen("output.txt", "w");
	fprintf(out,try_connect_to_WEB(p,num,&center,money,cast)? "YES" : "NO");
	free(p);
	fclose(out);

	return 0;
}



Но если N увеличить например в 100 раз, очевидно, что такое решение не будет подходящим. Как вы считаете, существует ли у этой задачи более быстрое решение ? Мне кажется что нет. Но я в этом не уверен.
...
Рейтинг: 0 / 0
22.09.2014, 09:31
    #38753233
Barlone
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Вопрос о существовании более быстрого алгоритма.
Ну это же классическая Задача коммивояжёра
...
Рейтинг: 0 / 0
22.09.2014, 09:33
    #38753236
Dima T
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Вопрос о существовании более быстрого алгоритма.
У тебя есть избыточность при вызове get_distance_between_Points(), т.к. считаешь каждый отрезок дважды. Т.е. проверяя точку А ты считаешь отрезок AB, проверяя точку B считаешь BA.

Операция извлечения корня достаточно тяжелая, поэтому можно сначала посчитать все отрезки в массив, а при расчете просто брать из массива.
...
Рейтинг: 0 / 0
22.09.2014, 09:49
    #38753241
SashaMercury
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Вопрос о существовании более быстрого алгоритма.
Простите, вы совершенно точно уверенны что это классическая задача коммивояжёра ?
...
Рейтинг: 0 / 0
22.09.2014, 09:52
    #38753242
SashaMercury
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Вопрос о существовании более быстрого алгоритма.
Дмитрий, согласен, спасибо :) Но это не решает основную проблему
...
Рейтинг: 0 / 0
22.09.2014, 09:59
    #38753244
Dima T
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Вопрос о существовании более быстрого алгоритма.
SashaMercuryДмитрий, согласен, спасибо :) Но это не решает основную проблему
А какая основная проблема? Ты спросил
SashaMercuryКак вы считаете, существует ли у этой задачи более быстрое решение ?
Я тебе его назвал.
...
Рейтинг: 0 / 0
22.09.2014, 13:09
    #38753425
SashaMercury
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Вопрос о существовании более быстрого алгоритма.
Нет, алгоритм практически не изменился. Полный перебор
...
Рейтинг: 0 / 0
22.09.2014, 13:23
    #38753453
Dima T
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Вопрос о существовании более быстрого алгоритма.
SashaMercuryНет, алгоритм практически не изменился. Полный перебор
От перебора ты не уйдешь. В худшем случае он будет полный.

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

Сомневаешься - затести оба варианта на большом наборе точек. Сгенери точки генератором случайных чисел и засеки время (функция clock() текущее время в мс).
...
Рейтинг: 0 / 0
22.09.2014, 14:25
    #38753520
Dima T
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Вопрос о существовании более быстрого алгоритма.
Посмотрел как корень вычисляется, оказывается сопроцессором (думал функция из сишной библиотеки), значит не тяжелая это операция, накладные расходы на организацию массива могут и замедлить расчет. Тестить надо :)
...
Рейтинг: 0 / 0
22.09.2014, 14:41
    #38753546
SashaMercury
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Вопрос о существовании более быстрого алгоритма.
Это интересно.

То есть всё-таки в худшем случае полный перебор ? Как это можно доказать ?
...
Рейтинг: 0 / 0
22.09.2014, 15:00
    #38753579
Dima T
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Вопрос о существовании более быстрого алгоритма.
SashaMercuryЭто интересно.

То есть всё-таки в худшем случае полный перебор ? Как это можно доказать ?
Ты же у нас математик, тебе и доказывать :)

Не получив длины всех отрезков нельзя решить (в худшем случае), а чтобы их получить - перебор всех пар точек.
...
Рейтинг: 0 / 0
22.09.2014, 15:35
    #38753627
SashaMercury
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Вопрос о существовании более быстрого алгоритма.
Я постараюсь узнать как это делается. Недавно в книжном магазине я читал Скиену, и встретил что-то про такие алгоритмы.
Спасибо. Меня гонят, доброго времени суток
...
Рейтинг: 0 / 0
22.09.2014, 15:36
    #38753629
SashaMercury
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Вопрос о существовании более быстрого алгоритма.
Хотел кстати недавно снова зайти почитать, а его уже купили ( полгода не покупали, а тут на тебе и купили
...
Рейтинг: 0 / 0
22.09.2014, 16:00
    #38753652
mayton
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Вопрос о существовании более быстрого алгоритма.
SashaMercury, Саша а ты пробовал менять long double на double?

Бинарник меняется?
...
Рейтинг: 0 / 0
22.09.2014, 16:35
    #38753716
mayton
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Вопрос о существовании более быстрого алгоритма.
BarloneНу это же классическая Задача коммивояжёра
Это не коммивояжер. У автора - кривенькая постановка которая к расчёту
проектов прокладки интернета имеет весьма отдалённое отношение. Расстояние
в километрах вообще редко определяло стоимость подключения. Гораздо важнее
- технология. Количество свободных портов, нагрузка и количество hops, лаги
и прочее.
...
Рейтинг: 0 / 0
22.09.2014, 16:38
    #38753722
mayton
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Вопрос о существовании более быстрого алгоритма.
Dima TПосмотрел как корень вычисляется, оказывается сопроцессором (думал функция из сишной библиотеки), значит не тяжелая это операция, накладные расходы на организацию массива могут и замедлить расчет. Тестить надо :)
Он вычисляется средствами библиотеки. Будет ли она использовать FPU или нет - отдельный вопрос.
И я заметил что ценность FPU-вычислений заметно ослаблена в пользу новых наборов команд.
...
Рейтинг: 0 / 0
22.09.2014, 18:45
    #38753871
Dima T
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Вопрос о существовании более быстрого алгоритма.
Затестил массив, добавил кэш длин отрезков в код SashaMercury, в дебаге чуть медленнее, в релизе вдвое медленнее
Исходник
Код: 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.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
#include <stdio.h>
#include <stdlib.h>
#include <math.h>

struct Point
{
	int id;
	int x;
	int y;
};

int use_sqrt1 = 0;
//расстояние между двумя точками в D^2
long double get_distance_between_Points(struct Point* p1, struct Point* p2)
{
#ifdef _DEBUG
		use_sqrt1++;
#endif
	long double dx = p1->x - p2->x;
	long double dy = p1->y - p2->y;
	return sqrt(dx*dx + dy*dy);
}

//вес графа. на входе адрес графа, количество точек, стартовая позиция
long double get_weight_graph(struct Point* p, int num, int s)
{
	long double res = 0;
	for (int i = 0; i < num; ++i)
	{
		res += get_distance_between_Points(p + i, p + s);
	}
	return res;
}

//Попытка провести интернет
bool try_connect_to_WEB(struct Point* p, int num, struct Point* center, long double money, int cast)
{
	long double res;
	int i = 0;
	do
	{
		res = get_weight_graph(p, num, i) + get_distance_between_Points(p + i, center);
		i += 1;
	} while (res*cast > money && i < num);
	return res*cast <= money;
}

// ***********************************************************************************************
#define POINT_COUNT 5000
#include <time.h>

long double* cache = NULL;
int use_sqrt2 = 0;
int use_cache = 0;

//расстояние между двумя точками в D^2
long double get_distance_between_Points2(struct Point* p1, struct Point* p2)
{
	long double res = cache[p1->id * POINT_COUNT + p2->id];
	if(res == 0) {
		long double dx = p1->x - p2->x;
		long double dy = p1->y - p2->y;
		res = sqrt(dx*dx + dy*dy);
		cache[p2->id * POINT_COUNT + p1->id] = res;
#ifdef _DEBUG
		use_sqrt2++;
	}  else {
		use_cache++;
#endif
	}
	return res;
}

//вес графа. на входе адрес графа, количество точек, стартовая позиция
long double get_weight_graph2(struct Point* p, int num, int s)
{
	long double res = 0;
	for (int i = 0; i < num; ++i)
	{
		res += get_distance_between_Points2(p + i, p + s);
	}
	return res;
}


bool try_connect_to_WEB2(struct Point* p, int num, struct Point* center, long double money, int cast)
{
	long double res;
	int i = 0;
	do
	{
		res = get_weight_graph2(p, num, i) + get_distance_between_Points(p + i, center);
		i += 1;
	} while (res*cast > money && i < num);
	return res*cast <= money;
}


int main(int argc, char** argv)
{
	srand((int)time(NULL));
	struct Point p[POINT_COUNT];
	int num = POINT_COUNT;
	int cast = 1;
	long double money = POINT_COUNT * 300;
	for(int i = 0; i < POINT_COUNT; i++) {
		p[i].id = i;
		p[i].x = rand() % 1000;
		p[i].y = rand() % 1000;
	}
	struct Point center;
	center.id = POINT_COUNT;
	center.x = rand() % 1000;
	center.y = rand() % 1000;

	// вариант SashaMercury
	clock_t time1 = clock();
	bool res1 = try_connect_to_WEB(p,num,&center,money,cast);

	// вариант кэшем
	clock_t time2 = clock();
	cache = (long double*)calloc(POINT_COUNT * POINT_COUNT, sizeof(long double));
	bool res2 = try_connect_to_WEB2(p,num,&center,money,cast);

	clock_t time3 = clock();
	printf("Res 1 %s time %d  sqrt=%d\n", res1 ? "YES" : "NO", time2 - time1, use_sqrt1);
	printf("Res 2 %s time %d  cache=%d sqrt=%d\n", res2 ? "YES" : "NO", time3 - time2, use_cache, use_sqrt2);

	system("pause");
	return 0;
}


Все-таки быстрее считать корни чем кэшировать.
...
Рейтинг: 0 / 0
22.09.2014, 22:45
    #38754042
BagaBaga
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Вопрос о существовании более быстрого алгоритма.
Немного странная задача.

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

Но! С учётом ограничения
авторДля того чтобы подключиться к сети всем N поросятам необходимо:
1. провести провод от точки подключения до домика одного из поросят;
2. от подключенного поросенка провести провода ко всем остальным.

алгоритм Прима или крускала придётся модифицировать, чтобы не рассматривал "лишние" рёбра ...
...
Рейтинг: 0 / 0
23.09.2014, 05:56
    #38754151
nevidomy
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Вопрос о существовании более быстрого алгоритма.
Примы и остовые деревья тут ни при чем. И это далеко не комивояжер.
Да и вообще решения основанные на графовых алгоритмах вряд ли помогут (колличество ребер в графе в данном случае O(n^2), так как это полный граф).
Скорее всего это задача на модификацию поиска геометрической медианы.
Вики:
http://en.wikipedia.org/wiki/Geometric_median
Конечно же в евклидовой метрике и в данном случае в 2D.

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

На практике же я бы решал эту задачу методом "имитации отжига" http://en.wikipedia.org/wiki/Simulated_annealing .
Он само собой являеться недетерминированным алгоритмом, но чаще всего получает AC на подобных задач. Как альтернатива, могу еще порекомендовать A* или генетические алгоритмы, на практике генетика будет хуже отжига, чисто мое опытное мнение.

Вообще задача (общая) намного проще решаеться для манхеттенской метрики, ну и как "не самое очевидное следствие" для суммы квадратов расстояний, подробности можно найти вот тут: http://stackoverflow.com/questions/12934213/how-to-find-out-geometric-median .
...
Рейтинг: 0 / 0
23.09.2014, 05:57
    #38754152
nevidomy
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Вопрос о существовании более быстрого алгоритма.
nevidomy,
omg... с тегами не разобрался :)
...
Рейтинг: 0 / 0
Форумы / Программирование [игнор отключен] [закрыт для гостей] / Вопрос о существовании более быстрого алгоритма. / 20 сообщений из 20, страница 1 из 1
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


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