Один раз в
год Джо и его друзья хотят посетить местную ярмарку в Эрлангене, называемую
Бергкирхвайх. В этом году они хотят совершить Kastenlauf (box run). Они
стартуют от дома Джо, имея одну коробку (Kasten) пива с двадцатью бутылками.
Чтобы их не мучила жажда, они пьют одну бутылку пива каждые 50 метров.
Поскольку
путь от дома Джо к Бергкирхвайх довольно долгий, они должны потребить больше
пива, чем взяли изначально. К счастью на пути имеются магазины, торгующие
пивом. Когда они посещают магазин, то могут отказаться от своих пустых бутылок
и купить новые, однако общее количество полных бутылок должно быть не больше
двадцати (ребята слишком ленивы, чтобы нести более одной полной коробки).
Вам заданы
координаты магазинов, дома Джо и расположения Бергкирхвайх. Напишите программу,
которая определит, смогут ли Джо и его друзья счастливо добраться до
Бергкирхвайх, или же пиво закончится на их пути.
Вход. Первая
строка содержит количество тесов t (t ≤ 50). Каждая строка начинается
количеством магазинов n (0 ≤ n ≤ 100), торгующих пивом.
Следующие n + 2 строки содержат
(именно в таком порядке) местоположение дома Джо, магазинов и Бергкирхвайх.
Местоположение задается двумя целочисленными координатами x и y (в метрах, -32768
≤ x, y ≤ 32767). Поскольку Эрланген представляет собой город в
виде прямоугольной сетки, то расстояние между двумя точками равно сумме
разностей координат (Манхетенская метрика).
Выход. Для
каждого теста вывести в отдельной строке либо "happy" (если Джо и его
друзья благополучно достигнут Бергкирхвайха), или "sad" (если у них
на пути закончится пиво).
Пример входа |
Пример выхода |
2 2 0 0 1000 0 1000 1000 2000 1000 2 0 0 1000 0 2000 1000 2000 2000 |
happy sad |
графы – поиск в глубину
Поскольку
количество бутылок, которое ребята могут нести с собой, равно 20, а через
каждые 50 метров следует выпить одну бутылку, то перемещаться они смогут только
между магазинами, расстояние между которыми не более 20 * 50 = 1000 метров.
Построим
граф, вершинами которого будут дом Джо, магазины и Бергкирхвайх. Ребро между
вершинами присутствует если только расстояние между ними не более 1000 метров.
То есть неориентированные ребра указывают возможные пути передвижения Джо и его
друзей.
Запускаем
поиск в глубину из дома Джо. Если из нее можно достичь Бергкирхвайх, то друзья
будут счастливы, иначе – нет.
Пример
Для
первого и второго примеров граф будет выглядеть следующим образом:
В первом
примере Джо с друзями могут достичь ярмарку Бергкирхвайх. Во втором – нет.
Передвигаться можно только между теми вершинами графа, расстояние между
которыми не больше 1000 метров.
Реализация алгоритма
Координаты
магазинов храним в (x[i], y[i]). Объявим граф передвижения g.
#define MAX 110
int x[MAX], y[MAX];
vector<vector<int>
> g;
vector<int> used;
Поиск в
глубину из вершины v.
void dfs(int
v)
{
used[v] = 1;
for(int i = 0; i <
g[v].size(); i++)
{
int to = g[v][i];
if (!used[to]) dfs(to);
}
}
Основная
часть программы. Читаем входные данные.
scanf("%d",&tests);
while(tests--)
{
scanf("%d",&n);
Поскольку входные данные содержат несколько тестов, то
очищаем массивы.
g.clear();
g.resize(n+2);
used.clear();
used.resize(n+2);
Читаем координаты дома Джо (x[0], y[0]), магазинов и
Бергкирхвайх (x[n – 1], y[n – 1]).
for(i = 0; i < n + 2; i++)
scanf("%d %d",&x[i],&y[i]);
Строим граф возможных передвижений. Из вершины (x[i], y[i]) можно перейти в вершину (x[j],
y[j]) если только расстояние между
ними не более 1000 метров. Граф неориентированный. Метрика манхетенская.
for(i = 0; i < n + 2; i++)
for(j = i + 1; j < n + 2; j++)
if (abs(x[i] - x[j]) + abs(y[i] - y[j]) <= 1000)
{
g[i].push_back(j);
g[j].push_back(i);
}
Стартуем из дома Джо. Запускаем поиск в глубину из
вершины 0.
dfs(0);
Если Бергкирхвайх достижим, то выводим “happy”, иначе
выводим “sad”.
if (used[n + 1]) puts("happy");
else puts("sad");
}
Реализация – матрица смежности
#include <stdio.h>
#include <string.h>
#define MAX 110
int tests, n, i, j;
int x[MAX], y[MAX];
int g[MAX][MAX], used[MAX];
int abs(int
x)
{
return (x < 0) ? -x : x;
}
void dfs(int
v)
{
used[v] = 1;
for(int i = 0; i <
n + 2; i++)
if (g[v][i] && !used[i]) dfs(i);
}
int main(void)
{
scanf("%d",&tests);
while(tests--)
{
scanf("%d",&n);
memset(g,0,sizeof(g));
memset(used,0,sizeof(used));
// 0 = Jo's house, start
// 1 .. n - stores selling beer
// n+1 - Bergkirchweih, finish
for(i = 0; i < n + 2; i++)
scanf("%d %d",&x[i],&y[i]);
for(i = 0; i < n + 2; i++)
for(j = i + 1; j < n + 2; j++)
if (abs(x[i] - x[j]) + abs(y[i] - y[j]) <= 1000)
g[i][j] =
g[j][i] = 1;
// Start from Jo's house
dfs(0);
// if Bergkirchweih is reached, then happy
if (used[n + 1]) puts("happy");
else puts("sad");
}
return 0;
}