Блог пользователя Vayne

Автор Vayne, 11 лет назад, По-русски

Всем доброй части суток, есть здесь среди задач — вот такая :

Задана квадратная матрица n × n, состоящая из неотрицательных целых чисел. Вам надо найти такой путь на ней, который

начинается в левой верхней ячейке матрицы;
каждой следующей ячейкой имеет правую или нижнюю от текущей;
заканчивается в правой нижней клетке.

Кроме того, если перемножить все числа вдоль пути и посмотреть на получившиеся произведение, то это число должно быть как можно менее «круглым». Иными словами оно должно заканчиваться на наименьшее возможное количество нулей.

Собственно, как решаю ее я :

Сначала смотрим, что может привести к образованию нулей( а именно множители 2, 5 и число 0 в ячейке матрицы ... )Далее прохожу по всем путям, следуя условию, что двигаться можно либо вниз, либо вправо — делаю это рекурсивно :

Количество делителей записываю в вектора, а сам путь записываю в вектор строк :

int masPath( bool F, std :: string S, uInt X, uInt Y, uInt N, uInt M, uInt M_1 ){

	if( Mas[X][Y] == 0 )
		F == 1;

	if( Mas[X][Y] % 5 == 0 )
		M++;

	if( Mas[X][Y] % 2 == 0 )
		M_1++;

	if( X == N - 1 && Y == N - 1 ){
		if( !F ){
			vec.push_back( M );
			vec_1.push_back( M_1 );
		}else
			vec.push_back( 1 );

		vec_2.push_back( S );
		return 1;
	}
	
	if( X != N - 1 )
		masPath( F, S + "D", X + 1, Y, N, M, M_1 );

	if( Y != N - 1 )
		masPath( F, S + "R", X, Y + 1, N, M, M_1 );


	return 0;
}

Затем нахожу минимум, и по его индексу вывожу путь :)

Собственно — программа раблотает вернее верного, все пути как на ладони, но как этого и следовало ожидать — ест столько, что можно лопнуть ( при N = 10 — 5 Mb ), да и постоянный вызов функции — тоже есть доволно много времени ... собственно на 11 тесте у меня ограничение памяти, но даже если его и убрать — т .е как то сократить, то в дальнейшем будет превышение времени ...

Разбор задач, я почитал — и собственно примерно все тоже самое ...Разве что, имеется ввиду какой — то иной способ обхода путей ... Вот у меня и вопрос, какой ?

Заранее благодарю :)

  • Проголосовать: нравится
  • -19
  • Проголосовать: не нравится

»
11 лет назад, # |
  Проголосовать: нравится +3 Проголосовать: не нравится

А собственно позвольте поинтересоваться какой разбор Вы читали? В нем(даже в обоих) речь идет о динамике, а у Вас перебор в явном виде. Примерно все тоже самое... — это Вы насчет идеи решения, но вот насчет реализации лучше все-таки считать ответ для каждой ячейки по одному разу, а не перебирать все возможные пути из одного конца таблицы в другой. Их всего-то С(2*n,n), что для того теста который у Вас упал(N = 20) равно примерно 10^11

  • »
    »
    11 лет назад, # ^ |
      Проголосовать: нравится +3 Проголосовать: не нравится

    Уж извиняюсь, за тупость, но как понять — считать для каждой ячейки по одному разу ?

    • »
      »
      »
      11 лет назад, # ^ |
      Rev. 2   Проголосовать: нравится +3 Проголосовать: не нравится

      Ну в чем принцип динамики..ответ для какого-то состояния пересчитывается исходя из каких-то других ответов, но считается то он только 1 раз, а зачем больше то ? Ты по сути что в своем решении делаешь, когда ты пришел в какую-то клетку, то дальше ты пытаешься найти путь из нее в правый нижний угол таблицы перемножение чисел на котором было как можно менее круглым.. Но дело в том что в клетку (х,у) ты попадаешь 2 раза из (х-1,у) и из (х,у-1), а значит считаешь выше сказанное 2 раза. А зачем ? Ведь можно запомнить ответ и 2 раз уже просто его заюзать.. так получится намного быстрее.

      P.S. Прочитай про динамическое программирование, информации предостаточно. Ну а если по теме, то в разборе вроде бы подробно расписано какая динамика и какие переходы.

      P.P.S. Прошу прощения, наврал немного... в клетку (x,y) ты попадаешь с 2 сторон:слева и сверху.. а попадаешь ровно столько раз, сколько существует путей из верхнего левого угла таблицы в эту клетку, это, как ты сам понимаешь, намного больше 2 :)