Разбор задачи «Зеркало в коридоре» и негодование

в 19:44, , рубрики: математика, негодование, олимпиадные задачи, Программирование

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

Разбор задачи «Зеркало в коридоре» и негодование - 1

Итак, сразу договоримся, что всяческих округлений и погрешностей, связанных с представлением чисел с плавающей точкой, у нас не будет. Работать будем исключительно с целочисленными переменными, для этого прибегнем к очевидным хитростям. Хотя, на самом деле, здесь будет мало программирования и много математики. В этой работе использованы справочные материалы по ВУЗовской математике, а точнее один параграф из главы «Основы линейной алгебры и аналитической геометрии» [1].

Для начала напомню текст задачи:

Простуженный Петя лежал в постели, как вдруг кто-то открыл дверь. Пете было лень вставать и он посмотрел в зеркало, чтобы увидеть кто пришёл. Известны координаты вошедшего (его можно считать материальной точкой), необходимо узнать, удасться ли Пете увидеть отражение вошедшего в зеркале. Зеркало имеет форму круга с центром в начале координат и расположено в плоскости ax + by + cz = 0. Петю тоже можно считать материальной точкой. Гарантируется, что Петя и незнакомец не лежат в плоскости зеркала и что Петя всегда видит отражающую сторону зеркала. Если изображение попадает на границу зеркала, то Петя видит вошедшего. Так как и Петю и вошедшего можно считать материальными точками, Петя может увидеть отражение вошедшего как сквозь вошедшего, так и сквозь свое собственное отражение.

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

Можно, конечно, рассмотреть даже и одномерный вариант, но смысла в нем мало, ибо зеркало превращается в точку и Петр увидит вошедшего только в том случае, когда они находятся по одну сторону от зеркала, т.е. если их координата имеет одинаковый знак.

Вычертим иллюстрацию к задаче:

Разбор задачи «Зеркало в коридоре» и негодование - 2

Обозначим Петю точкой S, незнакомца точкой T, зеркало — отрезок прямой image
Исходные данные: R — радиус зеркала, коэффициенты A и B;
image — координаты вошедшего;
image — координаты Петра.

Алгоритм решения следующий:
— Через точку T проводим прямую, перпендикулярную PQ;
— На этой прямой отмечаем точку T` симметричную точке T относительно PQ — это будет изображение вошедшего, которое увидит (или не увидит) Петя;
— Проведем прямую ST`;
— Найдем точку пересечения PQ и ST`;
— Проверим, принадлежит ли данная точка отрезку PQ

Итак, уравнение прямой, проходящей через точку T перпендикулярно image выглядит следующим образом:
image или image
image
Точка пересечения TT` и PQ является решением системы уравнений:
image
Домножим уравнения на A и B соответственно и сложим между собой:
image
image
image
image
Найденная точка image — проекция точки T на прямую PQ
Определим координаты точки T`:
image
image

Два шага позади. Найдем уравнение прямой ST`:
image или image
Подставим выражения для координат T`:
image
Уходим к целочисленному исчислению — умножаем уравнение на image:
image
Самое время ввести замену:
image
тогда уравнение ST` принимает вид: image

Точка пересечения PQ и ST` является решением системы:
image
image
image
image
image

Ну и, наконец, расстояние от центра координат до найденной точки: image
Уходим от радикалов: image
Теперь, если найденное R' будет не более заданного R, то наш несчастный Петр увидит все-таки вошедшего незнакомца.
В сравнении image обе части неравенства умножим на заведомо положительное (т.к. четная степень) image
т.е. нас интересует истинность выражения image

К чему я все это так подробно расписываю? Просто для того, чтобы показать какой объем работ должен проделать участник олимпиады для решения этой задачи, а ведь все эти формулы перпендикулярных прямых не входят в школьный курс математики, участник должен сам до них дойти логическим путем? При этом ему на эту задачу отведено в среднем 30 минут. Так ведь задача-то еще и не решена на самом-то деле. Во-первых надо все тоже самое проделать для трехмерного пространства, что еще более трудоемко, а во-вторых здесь не рассмотрено находятся ли мальчик и его гость по одну сторону от зеркала…

Чтож, нам-то цейтнот не грозит, поэтому продолжим.
Разберемся с «зазеркальем».
У меня такое решение (хотя оно тоже не сразу пришло в голову, сначала я думал о переходе к системе координат связанной с прямой зеркала, но там «некрасивые» тригонометрические функции) — через точки S и T проведем прямые параллельные заданной image. Параллельные прямые имеют кратные коэффициенты при x и y, т.е. image, разница только в свободном члене. Мы ничего выдумывать не будем и возьмем эти коэффициенты равными заданным A и B.
Тогда уравнение прямой, проходящей через точку S параллельно PQ имеет вид: image или image
Вот, в зависимости от знака свободного члена image прямая будет находиться с одной либо с другой стороны от заданной.
Аналогично для прямой, проходящей через T: image

Сделаем следующее: найдем значение произведения image и сравним его с нулем: если больше нуля — точки расположены по одну сторону от прямой, если меньше — по разные и Петя уже точно гостя своего не увидит, ну и промежуточный ноль — тоже удовлетворяет, т.к. в этом случае как минимум одна из точек лежит на заданной прямой.

Ну и напоследок приведу текст программы для трехмерного мира, т.е. для исходного условия задачи:

src

package ru.andrewn;

import static java.lang.System.out;

public class Program {

	public static void main(String[] args) {
		java.util.Scanner sc = new java.util.Scanner(System.in);
		
		out.println("Введите r:");
		int R = sc.nextInt();
		
		out.println("Введите a, b и c:");
		int A = sc.nextInt();
		int B = sc.nextInt();
		int C = sc.nextInt();
		
		out.println("Введите положение Петра (xп, yп и zп):");
		int xx = sc.nextInt();
		int yy = sc.nextInt();
		int zz = sc.nextInt();
		
		out.println("Введите положение входящего (x0, y0 и z0):");
		int x0 = sc.nextInt();
		int y0 = sc.nextInt();
		int z0 = sc.nextInt();
		
		if ( (A*x0+B*y0+C*z0)*(A*xx+B*yy+C*zz) >= 0 ) {
			int M = (B*B+C*C-A*A)*x0-2*A*B*y0-2*A*C*z0-(A*A+B*B+C*C)*xx;
			int N = (A*A+C*C-B*B)*y0-2*A*B*x0-2*B*C*z0-(A*A+B*B+C*C)*yy;
			int K = (A*A+B*B-C*C)*z0-2*A*C*x0-2*B*C*y0-(A*A+B*B+C*C)*zz;
			
			if ( (A*M+B*N+C*K)*(A*M+B*N+C*K)*R*R >=
					((B*N+C*K)*xx-B*M*yy-C*M*zz)*((B*N+C*K)*xx-B*M*yy-C*M*zz) +
					((A*M+C*K)*yy-A*N*xx-C*N*zz)*((A*M+C*K)*yy-A*N*xx-C*N*zz) +
					((A*M+B*N)*zz-A*K*xx-B*K*yy)*((A*M+B*N)*zz-A*K*xx-B*K*yy)) 
				out.println("Петр увидит входящего");
			else
				out.println("Петр не увидит входящего");
		}
		else
			out.println("Петр не увидит входящего");
		
		sc.close();
	}
}

Простите за кривизну кода, я далеко не программист.

Если будут желающие — могу приложить и математические выкладки для трехмерного мира.

Резюме

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

Литература

1. Корниенко, В.С. Справочный материал по математике: Пособие для самообразования [Электронный ресурс] / В.С. Корниенко; Волгогр. гос. с.-х. акад. Волгоград, 2010. 284 с.

Автор: AndrewN

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js