Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > IT форум > Помощь студентам
Регистрация

Восстановить пароль

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 11.02.2015, 08:04   #1
Poma][a
Новичок
Джуниор
 
Регистрация: 11.10.2011
Сообщений: 3,882
По умолчанию Задача на поиск оптимального пути в матрице

Путешествие на хамелеоне

Ограничение времени 1 секунда
Ограничение памяти 64Mb
Ввод стандартный ввод или input.txt
Вывод стандартный вывод или output.txt

Вот уже несколько лет в Зазеркалье проводится удивительная игра – «Гонки на хамелеоне». Игра состоит в следующем: имеется игровое поле размером NxМ, каждая клетка поля покрашена в некоторый цвет, который кодируется целым числом от 1 до К (1<=K<=10000). Игрок, верхом на хамелеоне, должен пробраться из верхней левой клетки игрового поля в нижнюю правую, при этом потратив минимальное количество яблок. Яблоко приходится отдать хамелеону за то, что он меняет свой цвет, попав в клетку другого цвета. Изначально хамелеон находится в клетке с координатами (1, 1), и имеет ее цвет. Он может перемещаться в 4-х направлениях в любую соседнюю клетку, имеющую с текущей общую сторону. Задание: определите минимальное количество яблок, которое придется скормить хамелеону, чтобы осуществить указанное путешествие.
Формат ввода

Первая строка содержит два числа N и М – размер игрового поля (2<=N, М<=100). Далее следует N строк, каждая содержит по М целых чисел, разделенных пробелом, кодирующих цвет клетки (1..10 000).
Формат вывода

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

Пример 1
Код:
5 4
1 1 1 2
2 1 2 3
3 1 2 3
1 1 3 3
1 1 1 3
Ответ :
Код:
1
Пример 2
Код:
5 4
1 2 3 4
2 2 3 4
3 3 3 4
4 4 4 4
5 5 5 5
Ответ :
Код:
4
Poma][a вне форума Ответить с цитированием
Старый 11.02.2015, 08:13   #2
Poma][a
Новичок
Джуниор
 
Регистрация: 11.10.2011
Сообщений: 3,882
По умолчанию

Утро доброе.
Задача, представленная выше была на городском этапе всероссийской олимпиады школьников по программированию(или информатике.. фиг знает)
Дык вот
Хотелось бы узнать, какое решение можно по праву назвать лучшим.

Вот это на полный балл
Код:
#include <iostream>
#include <vector>
#include <algorithm>

#define INF 1000000

using namespace std;

int main()
{
	int n, m;
	cin >> n >> m;

	vector<vector<int> > v(n + 2, vector<int>(m + 2, 0));
	vector<vector<int> > p(n + 2, vector<int>(m + 2, INF));

	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= m; j++)
			cin >> v[i][j];

	p[1][1] = 0;
	for (int k = 0; k < 5000; k++)
		for (int i = 1; i <= n; i++)
			for (int j = 1; j <= m; j++)
			{
				p[i][j] = min(p[i][j], p[i + 1][j] + (v[i + 1][j] != v[i][j]));
				p[i][j] = min(p[i][j], p[i - 1][j] + (v[i - 1][j] != v[i][j]));
				p[i][j] = min(p[i][j], p[i][j + 1] + (v[i][j + 1] != v[i][j]));
				p[i][j] = min(p[i][j], p[i][j - 1] + (v[i][j - 1] != v[i][j]));
			}

	cout << p[n][m];
	return 0;
}
Но оно мне не нравится.. Число 5к пришлось долго искать.. Да и само оно совсем не ахти..
Написал некий аналог bfs. Фишка в том, что bfs требует, чтобы первый найденный путь и был оптимальным, в нашем случае это ессесно не так..
Тогда я решил использовать кучу (aka очередь с приоритетом), чтобы хранить и быстро выбирать минимальный элемент (а он выбирается так : минимальный вес на текущий момент, если же у нас есть несколько элементов с минимальным весом, то я выбираю тот, у которого № волны меньше)
Код:
#include <iostream>
#include <queue>
#include <functional>

#define INF 1000000

using namespace std;

struct st
{
	int x, y, w, p;
	friend bool operator < (const st& a, const st& b);
};
bool operator < (const st& a, const st& b)
{
	if (a.w == b.w) return a.p < b.p;
	return a.w > b.w;
}

int main()
{
	int n, m;
	cin >> n >> m;
	vector<vector<int> > v(n + 2, vector<int>(m + 2)), p(n + 2, vector<int>(m + 2));

	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= m; j++)
			cin >> v[i][j];

	priority_queue<st, vector<st> > q;
	st t;
	t.x = 1; t.y = 1; t.w = 1; t.p = 0;
	vector<vector<int> > use(n + 2, vector<int>(m + 2, INF));
	q.push(t);
	use[1][1] = 1;
	while (!q.empty())
	{
		t = q.top(); q.pop();
		if (p[t.x][t.y] != 0 && p[t.x][t.y] < t.w) continue;
		p[t.x][t.y] = t.w;
		if (v[t.x - 1][t.y] != 0 && p[t.x - 1][t.y] == 0 && use[t.x - 1][t.y] > t.w + (v[t.x][t.y] != v[t.x - 1][t.y]))
		{
			st temp;
			temp.x = t.x - 1;
			temp.y = t.y;
			temp.w = t.w + (v[t.x][t.y] != v[temp.x][temp.y]);
			temp.p = t.p + 1;
			q.push(temp);
			use[t.x+1][t.y] = temp.w;
		}
		if (v[t.x + 1][t.y] != 0 && p[t.x + 1][t.y] == 0 && use[t.x + 1][t.y] > t.w + (v[t.x][t.y] != v[t.x + 1][t.y]))
		{
			st temp;
			temp.x = t.x + 1;
			temp.y = t.y;
			temp.w = t.w + (v[t.x][t.y] != v[temp.x][temp.y]);
			temp.p = t.p + 1;
			q.push(temp);
			use[t.x+1][t.y] = temp.w;
		}
		if (v[t.x][t.y - 1] != 0 && p[t.x][t.y - 1] == 0 && use[t.x][t.y - 1] > t.w + (v[t.x][t.y] != v[t.x][t.y - 1]))
		{
			st temp;
			temp.x = t.x;
			temp.y = t.y - 1;
			temp.w = t.w + (v[t.x][t.y] != v[temp.x][temp.y]);
			temp.p = t.p + 1;
			q.push(temp);
			use[t.x][t.y - 1] = temp.w;
		}
		if (v[t.x][t.y + 1] != 0 && p[t.x][t.y + 1] == 0 && use[t.x][t.y + 1]> t.w + (v[t.x][t.y] != v[t.x][t.y + 1]))
		{
			st temp;
			temp.x = t.x;
			temp.y = t.y + 1;
			temp.w = t.w + (v[t.x][t.y] != v[temp.x][temp.y]);
			temp.p = t.p + 1;
			q.push(temp);
			use[t.x][t.y + 1] = temp.w;
		}
	}

	cout << p[n][m] - 1;

	return 0;
}
Решение работает очень быстро, что сообственно я и хотел, но не всегда корректно..
Вот такой вот вердикт тестирующей системы
Код:
Время      Память  № первого проблемного теста  балл
10ms     512.00Kb    16	                          21
Когда первый вариант
Код:
	
0.597s   380.00Kb  - 25
UPDATE

Ах да, к сожалению, свой логин\пароль я потерял, и тестирую на сайте с аккаунта друзей.. Посему дать его Вам я не могу, уж пардоньте..
И еще.. Тестирующая система кушает код только на крестах и паскале (Free\Delphi)

Последний раз редактировалось Poma][a; 11.02.2015 в 08:39.
Poma][a вне форума Ответить с цитированием
Старый 11.02.2015, 08:40   #3
rrrFer
Санитар
Старожил
 
Аватар для rrrFer
 
Регистрация: 04.10.2008
Сообщений: 2,577
По умолчанию

Первый алгоритм оптимален. Лично я не вижу как этот АЛГОРИТМ можно оптимизировать, разве что эвристикой...
Я не понял откуда 5000 в примере, если это количество яблок - то должно быть 10000.

Мне кажется bfs тут неуместен.Или ты должен будешь запустить его 10 тысяч раз для разного количества яблок, но врядли это будет эффективнее.
rrrFer вне форума Ответить с цитированием
Старый 11.02.2015, 08:42   #4
Poma][a
Новичок
Джуниор
 
Регистрация: 11.10.2011
Сообщений: 3,882
По умолчанию

Цитата:
Я не понял откуда 5000 в примере, если это количество яблок - то должно быть 10000.
Именно поэтому и не нравится..
Код:
for (int k = 0; k < 10000; k++)
Такой вариант дает TL на одном тесте

Код:
for (int k = 0; k < 1000; k++)
А такой WA на двух

Цитата:
Мне кажется bfs тут неуместен.Или ты должен будешь запустить его 10 тысяч раз для разного количества яблок, но врядли это будет эффективнее.
Не думаю..

Последний раз редактировалось Poma][a; 11.02.2015 в 08:45.
Poma][a вне форума Ответить с цитированием
Старый 11.02.2015, 08:51   #5
FPaul
Форумчанин
 
Регистрация: 25.01.2015
Сообщений: 474
По умолчанию

Я понимаю, что в 1-м алгоритме 10'000 было бы уместнее. А если добавить проверку на то, что во время очередной итерации по k путь (p[][]) не был улучшен и в таком случае прекратить поиск.
В поиске по алгоритмам на графах (e-maxx) увидел название "алгоритм Дейкстры за O (M log N)", который бы сюда подошёл. Но еще не успел с ним ознакомиться.
FPaul вне форума Ответить с цитированием
Старый 11.02.2015, 08:58   #6
Poma][a
Новичок
Джуниор
 
Регистрация: 11.10.2011
Сообщений: 3,882
По умолчанию

Цитата:
В поиске по алгоритмам на графах (e-maxx) увидел название "алгоритм Дейкстры за O (M log N)", который бы сюда подошёл.
Неа..
Нам просто не сделать такой граф
Poma][a вне форума Ответить с цитированием
Старый 11.02.2015, 09:03   #7
FPaul
Форумчанин
 
Регистрация: 25.01.2015
Сообщений: 474
По умолчанию

А по поводу "добавить проверку на то, что во время очередной итерации по k путь (p[][]) не был улучшен и в таком случае прекратить поиск"?
FPaul вне форума Ответить с цитированием
Старый 11.02.2015, 09:09   #8
Poma][a
Новичок
Джуниор
 
Регистрация: 11.10.2011
Сообщений: 3,882
По умолчанию

Щас напишу
Все прошло! Пасиб

Но все равно не нравится..
Хочется чего-нить более оптимального..

Последний раз редактировалось Poma][a; 11.02.2015 в 09:14.
Poma][a вне форума Ответить с цитированием
Старый 11.02.2015, 09:21   #9
FPaul
Форумчанин
 
Регистрация: 25.01.2015
Сообщений: 474
По умолчанию

Оптимально - от [1,1] последовательно искать минимальные пути ко всем узлам графа. И на основе минимумов продвигаться к следующему узлу. Возможно, улучшая предыдущие оценки.
FPaul вне форума Ответить с цитированием
Старый 11.02.2015, 09:22   #10
Poma][a
Новичок
Джуниор
 
Регистрация: 11.10.2011
Сообщений: 3,882
По умолчанию

Если мы будет улучшать предыдущие оценки, то нужно будет все снова пересчитывать..
Poma][a вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Задача "Построение оптимального ж/д пути" (Delphi, курсовая работа) RomBe Фриланс 7 24.02.2014 17:18
Поиск оптимального пути из точки A в точку Б spirit-ua Общие вопросы Delphi 5 14.02.2014 13:36
Нахождения оптимального пути linkoln_7 Общие вопросы C/C++ 1 02.02.2014 00:18
создание графа по матрице и поиск кратчайшего пути из одного графа в другой lexflax Общие вопросы C/C++ 1 06.09.2012 07:32
"Поиск оптимального пути движения снегоочистительных машин с учетом приоритета дорог" Пролог Kvax Помощь студентам 4 21.12.2008 22:18