А394г

Задача
Дана целочисленная квадратная матрица порядка [latex]n[/latex]. Найти номера строк, элементы каждой из которых образуют образуют монотонную последовательность (монотонно убывающую или монотонно возрастающую).

*Строки матрицы нумеруются с единицы, потому их номера в выводе больше соответствующих индексов в массиве на единицу.
Тесты

[latex]n[/latex] Матрица Результат Комментарий
1 0 1 Квадратная матрица первого порядка состоит из одного элемента, следовательно, является и монотонно возрастающей, и монотонно убывающей.
3
1 1 1
2 2 2
3 3 3
Все элементы каждой строки попарно равны.
4
1 2 2 1
0 1 2 3
0.3 11 -2 3
0 0 1 1
2 В прочих строках монотонность нарушается
3
1 2 2
-1 10 15
3 2 1
2, 3 В первой строке последовательность возрастает нестрого.

Алгоритм решения

  1. Анализировать строку на монотонность можно при помощи знака разности соседних элементов. Если при движении по строке слева направо знак изменяется, последовательность не может быть монотонной (дополнительное ограничение для строгой монотонности: разность не должна равняться нулю).
  2. Отдельно следует рассматривать случай [latex]n \le 1[/latex]. По определению, последовательность [latex]\left\{ { a }_{ n } \right\}[/latex] — монотонна [latex]\Leftrightarrow \forall i,j\in N, j>i: a_{ i }\prec a_{ j } (a_{ i }\succ a_{ j })[/latex]. Последовательность из одного элемента имеет вид [latex]\left\{a_{n}\right\} = a_{1}[/latex], следовательно, невозможно выбрать такие [latex]i,j \in N ,j>i[/latex], чтобы выполнилось условие строгой монотонности. Рассмотренный пример является частным случаем понятия «vacuous truth», часто применяемого при доказательстве теорем.

Программный код

Детали реализации

  1. Считывание элементов строки может прекратиться в трех случаях: если монотонность сменяется с возрастания на убывание (или наоборот), или если найдены два равных соседних элемента. Для выхода из внутреннего цикла применяется присваивание [latex]j = n[/latex].
  2. Для корректной работы внутреннего цикла первый элемент строки считывается перед ним.
  3. Проверить, изменяется ли знак разности соседних элементов последовательности можно двумя способами: первый подразумевает умножение двух разностей, второй — реализацию функции signum(). Так как при умножении можно выйти за границы типа, выбран был второй способ.

Программа доступна для тестирования по ссылке: http://ideone.com/n60As6.
Реализация на Java: http://ideone.com/CnFow1

Related Images:

9 thoughts on “А394г

  1. А я не согласен, что последовательность из одного элемента не может быть монотонной. Как Вы ее определяете? Скорее всего, там что-то в духе «для любой пары соседних элементов выполняется неравенство…» В случае с одним элементом пар не будет вообще, а значит неравенство не нарушится.

    • Мне стало интересно: в самом деле, а может ли последовательность, содержащая меньше двух элементов, быть монотонной? Сам точного ответа на этот вопрос я найти не смог, обратился к преподавателям и старшим товарищам, а те рассказали о понятии vacuous truth (http://en.wikipedia.org/wiki/Vacuous_truth) в чистой математике и помогли правильно трактовать определение.
      Спасибо Вам за замечание, теперь я понимаю причины истинности факта, сначала показавшегося мне контринтуитивным.

  2. Дополню.
    Я ожидал, что Вы будете вычислять разность между текущим элементом и предыдущим. Если эта разность сменила знак, то монотонность нарушена. Смена знака проверяется, например, как знак произведения. С небольшим риском, конечно. Если произведение соседних разностей стало отрицательным, монотонности нет.
    Кстати, если размер 2, то ответ можно угадать 🙂

    • При умножении можно выйти за границы типа, поэтому я реализовал функцию signum(). В остальном, идея та же. Предложенный Вами подход действительно позволяет сократить размер программы, спасибо за замечание.

    • В данном случае Вы ошибаетесь. У Вас числа принадлежат типу double. При умножении для слишком больших чисел получится +inf или -inf, а для маленьких -0 или +0. Т.е. знак сохраняется. Во втором случае к сожалению не работает прямое сравнение с нулём. Приходится делать так: copysign(1,x*y)<0

  3. Кроме того, есть серьезное ощущение, что решение не работает, в том числе и на тестах, предложенных Вами. К примеру, на моем компьютере на тест
    4
    1 2 2 1
    0 1 2 3
    0.3 11 -2 3
    0 0 1 1
    Я получил ответ
    2 3 4
    Как минимум, ошибка состоит в том, что Вы, найдя «несоответствие», решаете не читать строку дальше. А куда тогда пойдет ввод этой строки? В следующую строку, разумеется.

    Мораль такова: не нужно создавать оптимизации там, где они не нужны.

    • Ваша правда, «premature optimization is the root of all evil.», как говорил Дональд Кнут. Не подумал об этом, исправил.

Добавить комментарий