Educational Round #3 — Разборы
Найдем максимальный элемент массива. Затем выполняем повторный проход по массиву, чтобы подсчитать количество максимальных элементов.
Объявим рабочий массив.
int m[101];
Читаем входной массив. Находим его максимальный элемент .
scanf("%d", &n);
max = -2000000000;
for (i = 0; i < n; i++)
{
scanf("%d", &m[i]);
if (m[i] > max) max = m[i];
}В переменной подсчитываем количество максимальных эементов.
cnt = 0; for (i = 0; i < n; i++) if (m[i] == max) cnt++;
Выводим ответ.
printf("%d\n", cnt);В час пик на остановку одновременно подъехали три маршрутных такси, следующие по одному маршруту, в которые тут же набились пассажиры. Водители заметили, что количество людей в разных маршрутках разное, и решили пересадить часть пассажиров так, чтобы в каждой маршрутке было одинаковое число пассажиров. Определите, какое наименьшее количество пассажиров придется пересадить для этого.
Вход. Три натуральных числа, не превосходящих — количество пассажиров в первой, второй и третьей маршрутках соответственно.
Выход. Выведите одно число — наименьшее количество пассажиров, которое требуется пересадить. Если это выполнить невозможно, то выведите IMPOSSIBLE.
1 2 3
1
Пусть — количество людей в первой, второй и третьей маршрутках. Для того чтобы после пересадки количество людей в маршрутках было одинаковое, необходимо чтобы сумма делилась на .
Пусть — количество людей, которое должно находиться в каждой маршрутке после пересадки. Тогда из каждой маршрутки следует пересадить в какую-то другую столько людей, чтобы в ней осталось ровно . Это возможно только если в маршрутке изначально находится больше пассажиров. Например, из первой маршрутки следует пересадить людей, если только . Со второй маршрутки следует пересадить людей (если ). Из третьей маршрутки следует пересадить людей (если ).
Читаем входные данные.
scanf("%d %d %d",&a,&b,&c);Если общая сумма людей не делится на , то выводим IMPOSSIBLE.
if((a + b + c) % 3 != 0)
puts("IMPOSSIBLE");
else
{
res = 0;Вычисляем количество людей в маршрутках после пересадки.
d = (a + b + c) / 3;
В переменной считаем количество пересаживаемых людей.
if (a > d) res += a - d; if (b > d) res += b - d; if (c > d) res += c - d;
Выводим ответ.
printf("%d\n",res);
}Огромное бедствие произошло сегодня утром в кафе, в котором Вы привыкли перекусывать во время учебы в университете. Уборщица Лариса Ивановна во время подметания пола уронила один из шкафов, в котором хранились все кухонные принадлежности. Все содержимое шкафа было разбросано по полу. К счастью, он содержал только кастрюли с крышками. Тем не менее, некоторые из них погнулись или сломались, поэтому были выброшены.
Теперь школьный учитель хочет подсчитать потери и выяснить, как много новых кастрюль и крышек следует купить. Но сначала следует выяснить, сколько оставшихся кастрюль можно накрыть оставшимися крышками.
Кастрюли и крышки круглые. Крышка может покрыть кастрюлю, если только радиус крышки не меньше радиуса кастрюли.
Вход. Первая строка содержит числа — количество оставшихся кастрюль и крышек. Вторая строка содержит целых чисел — радиусы оставшихся кастрюль. Третья строка содержит целых чисел — радиусы оставшихся крышек.
Выход. Выведите одно число — наибольшее количество кастрюль, которое может быть покрыто имеющимися крышками.
5 5 4 8 1 2 5 7 2 4 6 5
4
Отсортируем по возрастанию радиусы крышек и радиусы кастрюль. Для самой маленькой кастрюли найдем наименьшую крышку, которой ее можно накрыть. Далее для второй наименьшей кастрюли найдем наименьшую ей подходящую крышку и так далее. Ответом будет количество кастрюль, которое можно покрыть крышками.
Пример
Рассмотрим какому наибольшему числу кастрюль можно подобрать крышки для заданного примера.
Объявим массивы, в которых будем хранить радиусы кастрюль и крышек.
#define MAX 1010 int pan[MAX], lid[MAX];
Читаем входные данные.
scanf("%d %d",&n,&m);
for(i = 0; i < n; i++)
scanf("%d",&pan[i]);
for(i = 0; i < m; i++)
scanf("%d",&lid[i]);Сортируем радиусы кастрюль и крышек.
sort(pan,pan+n); sort(lid,lid+m);
Используя жадный метод, ищем каждый раз наименьшую крышку, которой можно накрыть наименьшую кастрюлю.
for (i = j = 0; (i < n) && (j < m); j++) if (pan[i] <= lid[j]) i++;
Выводим количество накрытых кастрюль.
printf("%d\n",i);Попав в пещеру с сокровищами, Алладин не стал брать старую почерневшую лампу. Вместо этого он принялся заполнять свой рюкзак золотыми монетами и драгоценными камнями. Конечно, ему хотелось забрать всё, но чудес не бывает — рюкзак имеет ограниченную грузоподъёмность и может не выдержать слишком большой вес.
Много раз он выкладывал одни предметы и заменял их другими, стремясь максимально увеличить общую стоимость содержимого рюкзака.
Требуется определить максимальную стоимость груза, который Алладин сможет унести.
Будем считать, что в пещере есть предметы различных типов, причём количество предметов каждого типа не ограничено. Рюкзак может выдержать вес не более . Каждый предмет типа имеет вес и стоимость .
Вход. В первой строке заданы два натуральных числа и — максимальный вес предметов в рюкзаке и количество типов предметов.
Далее следуют строк, каждая из которых содержит два числа и — вес и стоимость предмета типа .
Выход. Выведите максимальную стоимость груза, который можно унести, не превышая предельный вес .
10 2 5 10 6 19
20
Пусть — максимальная стоимость груза весом не более , если разрешено использовать только предметы первых типов.
Рассмотрим два возможных варианта при составлении груза весом :
Не использовать предмет -го типа: в этом случае оптимальное значение не изменится, то есть
Использовать предмет -го типа: тогда его вес займёт часть вместимости рюкзака, а стоимость увеличится на , то есть
Так как требуется максимизировать стоимость груза, получаем рекуррентное соотношение:
Базовые случаи:
Пусть функция вычисляет максимальную стоимость груза, который можно собрать в рюкзак весом не более , используя первые типов предметов. Тогда имеет место рекуррентное соотношение:
Осталось вычислить значение функции используя мемоизацию.
Объявим рабочие массивы:
— вес предмета -го типа;
— стоимость предмета -го типа;
— максимальная стоимость груза весом не более ;
#define MAXW 252 #define MAXN 37 int w[MAXN], p[MAXN]; int dp[MAXW];
Читаем входные данные.
scanf("%d %d", &s, &n);
for (i = 0; i < n; i++)
scanf("%d %d", &w[i], &p[i]);Последовательно обрабатываем типов предметов.
for (k = 0; k < n; k++)
{Пересчитываем значения массива , учитывая возможность использования предметов типа . Поскольку количество предметов каждого типа не ограничено, каждый предмет можно выбирать несколько раз.
for (i = w[k]; i <= s; i++)
dp[i] = max(dp[i], dp[i - w[k]] + p[k]);
}Выводим ответ.
printf("%d\n", dp[s]);Реализация алгоритма — рекурсия
Объявим рабочие массивы:
— вес предмета -го типа;
— стоимость предмета -го типа;
— максимальная стоимость груза весом не более ;
#define MAXW 252 #define MAXN 37 #define INF 2000000000 int w[MAXN], v[MAXN]; int dp[MAXN][MAXW];
Функция вычисляет максимальную стоимость груза, который можно собрать в рюкзак весом не более , используя первые типов предметов.
int f(int k, int s)
{Если или , то рюкзак пуст, и его стоимость равна .
if (k == 0 || s == 0) return 0;
Если , то мы превысили допустимый вес, и этот вариант не имеет смысла. Поэтому возвращаем ( — это некоторое большое число).
if (s < 0) return -INF;
Если значение уже вычислено, то возвращаем его.
if (dp[k][s] != -1) return dp[k][s];
Вычисляем значение и запоминаем его в .
return dp[k][s] = max(f(k - 1, s), f(k, s - w[k]) + v[k]); }
Основная часть программы. Читаем входные данные.
scanf("%d %d", &s, &n);
for (i = 1; i <= n; i++)
scanf("%d %d", &w[i], &v[i]);Вычисляем и выводим ответ.
memset(dp, -1, sizeof(dp));
printf("%d\n", f(n, s));В подчинении у короля лемуров Джулиана находится ровно лемуров — по два лемура каждого из видов. Джулиан обожает вечеринки, поэтому каждый вечер устраивает тусовку. Однако в VIP-зоне, к сожалению, хватает мест только для него самого и ещё лемуров.
Поскольку Джулиан не любит повторяться, он старается каждый раз приглашать в VIP-зону такой набор лемуров, который ранее ещё не встречался. Два лемура одного вида считаются неразличимыми. Два набора лемуров считаются одинаковыми, если они совпадают как мультимножества видов лемуров.
Помогите Джулиану определить, сколько различных вечеринок он сможет провести. Так как ответ может быть очень большим, выведите его по модулю .
Вход. В одной строке заданы два целых числа и — количество видов лемуров и число мест в VIP-зоне (не считая самого Джулиана).
Выход. Выведите одно число — количество различных вечеринок по модулю .
3 3
7
4 3
16
На мест некоторые виды будут представлены двумя лемурами, а некоторые одним. Пусть выбрано пар лемуров (то есть видов представлены двумя особями). Сделать такой выбор можно способами. После этого в VIP зоне останется свободных мест. Эти места можно занять лемурами из оставшихся видов, выбирая по одному лемуру из каждого. Количество способов выбрать таких лемуров вычисляется по формуле .
Так как значение может принимать любое целое значение от до , получаем итоговый ответ как сумму по всем возможным :
Пример
Рассмотрим второй пример, в котором есть пары лемуров и места в VIP-зоне. По формуле получаем:
Выпишем только ненулевые слагаемые. Значение будем считать равным нулю, если выполняется одно из трех неравенств: , или .
Обозначим лемуров буквами , где одинаковые буквы соответствуют лемурам одного вида.
Слагаемому соответствует ситуация, когда ни одна пара лемуров одного вида не выбрана, то есть каждый из трёх выбранных лемуров принадлежит разным видам. Возможные четыре выборки следующие:
Рассмотрим слагаемое . В этом случае из одного вида выбираются два лемура (существует варианта такого выбора). На оставшееся одно место выбирается один лемур из трёх оставшихся видов. Таким образом, всего возможно различных вариантов:
Очевидно, что разместить на местах по два лемура из двух разных видов невозможно. Поэтому все остальные слагаемые суммы равны нулю.
Объявим константы.
#define MAX 1000001 #define MOD 1000000007
Объявим массивы:
содержит факториалы чисел по модулю ;
содержит значения, обратные факториалам чисел по модулю :
fact[n] = n! mod 1000000007 factinv[n] = n! -1 mod 1000000007 typedef long long ll; ll fact[MAX], factinv[MAX];
Функция pow вычисляет степень числа по модулю: .
ll pow(ll x, ll n, ll p)
{
if (n == 0) return 1;
if (n % 2 == 0) return pow((x * x) % p, n / 2, p);
return (x * pow(x, n - 1, p)) % p;
}Функция inverse находит число, обратное по простому модулю . Поскольку — простое число, по малой теореме Ферма выполняется равенство:
Это равенство можно переписать в виде:
откуда следует, что обратным к является число .
ll inverse(ll x, ll p)
{
return pow(x, p - 2, p);
}Функция Cnk вычисляет значение биномиального коэффициента по следующей формуле:
ll Cnk(int n, int k)
{
return ((fact[n] * factinv[k]) % MOD * factinv[n - k]) % MOD;
}Основная часть программы. Читаем входные данные.
scanf("%d %d", &k, &n);Заполняем массивы факториалов и .
fact[0] = 1; for (i = 1; i < MAX; i++) fact[i] = (fact[i - 1] * i) % MOD; factinv[0] = 1; for (i = 1; i < MAX; i++) factinv[i] = inverse(fact[i], MOD);
Вычисляем ответ по формуле . Значение биномиального коэффициента считаем равным нулю, если выполняется одно из трех условий: , или .
res = 0;
for (i = 0; i <= k; i++)
{
if (n - 2 * i < 0 || k - i < 0 || n - 2 * i > k - i) continue;
res = (res + Cnk(k, i) * Cnk(k - i, n - 2 * i)) % MOD;
}Выводим ответ.
printf("%lld\n", res);Дано дерево с вершинами, где вершина с номером содержит монет. Выберите такое подмножество вершин, чтобы никакие две из них не были смежными (то есть не соединены ребром), а сумма монет в выбранных вершинах была максимальной.

Вход. Первая строка содержит количество вершин в дереве. Каждая из следующих строк содержит два целых числа и , задающих ребро в дереве. Последняя строка содержит неотрицательных целых чисел — количество монет в каждой вершине дерева.
Выход. Выведите максимальную возможную сумму монет, которую можно получить, выбрав подмножество вершин дерева с условием отсутствия смежных вершин.
5 1 2 1 3 2 4 2 5 1 5 7 1 2
12
5 1 2 1 3 2 4 2 5 3 7 5 10 1
16
Пусть — вершина дерева. Обозначим через:
наибольшую сумму монет, которую можно собрать из поддерева с корнем , если монеты в вершине мы берем.
наибольшую сумму монет, которую можно собрать из поддерева с корнем , если монеты в вершине мы не берем.
Тогда ответом на задачу будет , если взять первую вершину за корень дерева.
Определим рекурсивно приведенные функции:
Если монеты в вершине мы берем, то брать монеты из ее сыновей нельзя:
Если монеты в вершине мы не берем, то из её сыновей можно или брать, или не брать монеты. Из этих двух вариантов следует выбрать тот, в котором сумма монет максимальна:
Если — лист дерева с монетами, то функции в нем примут следующие значения: и .
Пример
Расставим метки на вершинах деревьев из примеров.
Для первого примера имеем:
;
;
;
;
Для второго примера имеем:
;
;
;
;
Упражнение
Расставьте метки на вершинах дерева:
Объявим рабочие массивы.
vector<vector<int> > g; vector<int> dp1, dp2, cost;
Функция dfs реализует поиск в глубину. Вычисляем значения и во всех вершинах дерева.
void dfs(int v, int p = -1)
{
dp1[v] = cost[v];
dp2[v] = 0;
for (int to : g[v])
{
if (to == p) continue;
dfs(to, v);
dp1[v] += dp2[to];
dp2[v] += max(dp1[to], dp2[to]);
}
}Основная часть программы. Читаем дерево и массив монет.
scanf("%d",&n);
g.resize(n+1);
for(i = 1; i < n; i++)
{
scanf("%d %d",&u,&v);
g[u].push_back(v);
g[v].push_back(u);
}
dp1.resize(n+1); dp2.resize(n+1);
cost.resize(n+1);
for(i = 1; i <= n; i++)
scanf("%d",&cost[i]);Пусть корень дерева находится в вершине . Запускаем из нее поиск в глубину.
dfs(1);
Вычисляем и выводим ответ.
ans = max(dp1[1], dp2[1]);
printf("%d\n",ans);Дан прямоугольник размером . Ваша задача — разрезать его на квадраты. За один ход можно выбрать один из прямоугольников и разрезать его на два новых прямоугольника так, чтобы все длины сторон оставались целыми числами. Определите наименьшее количество ходов, которое потребуется для этого.
Вход. Два целых числа и .
Выход. Выведите минимальное количество ходов, необходимое для разрезания прямоугольника на квадраты.
3 5
3
5 10
1
Пусть — наименьшее количество ходов, за которое прямоугольник размером можно разрезать на квадраты. Будем хранить это значение в ячейке .
Если прямоугольник уже является квадратом , разрезы не требуются, поэтому .
Прямоугольник можно разрезать либо вертикальным, либо горизонтальным разрезом. Рассмотрим сначала вертикальный разрез.
При вертикальном разрезе прямоугольник делится на два прямоугольника: и . Чтобы полученные прямоугольники были невырожденными, должно выполняться условие . Затем рекурсивно решаем задачу для каждого из этих двух прямоугольников и добавляем к результату, так как мы сделали один вертикальный разрез. При этом выбираем такое , для которого сумма наименьшая:
Для случая горизонтального разреза получаем аналогичную формулу:
Остаётся выбрать минимальное значение среди этих двух вариантов.
Пример
В первом тесте требуется выполнить разреза:
Первым разрезом прямоугольник разделяется на и ;
Вторым разрезом прямоугольник разделяется на и ;
Третьим разрезом прямоугольник разделяется на и ;
Объявим константы и рабочий массив.
#define MAX 501 #define INF 0x3F3F3F3F int dp[MAX][MAX];
Функция возвращает наименьшее количество ходов, за которое прямоугольник размером можно разрезать на квадраты.
int f(int a, int b)
{Если прямоугольник уже является квадратом , разрезы не требуются.
if (a == b) return 0;
Если значение еще не вычислено , то вычисляем его.
if (dp[a][b] == INF)
{Выполняем все возможные вертикальные разрезы.
for (int k = 1; k < b; k++)
dp[a][b] = min(dp[a][b], f(a, k) + f(a, b - k) + 1);Выполняем все возможные горизонтальные разрезы.
for (int k = 1; k < a; k++)
dp[a][b] = min(dp[a][b], f(k, b) + f(a - k, b) + 1);
}Возвращаем результат .
return dp[a][b]; }
Основная часть программы. Читаем размеры прямоугольника и .
scanf("%d %d", &a, &b);Вычисляем и выводим ответ.
memset(dp, 0x3F, sizeof(dp));
printf("%d\n", f(a, b));Закон Джунглей гласит совершенно ясно: каждый волк, заведя семью, может покинуть свою Стаю. Но как только его волчата подрастут и окрепнут, он обязан привести их на Совет Стаи, который обычно собирается раз в месяц, в полнолуние, и представить всем остальным волкам.
Отец Волк дождался, пока его волчата немного подросли и начали понемногу бегать, и в одну из тех ночей, когда собиралась Стая, повёл их — вместе с Маугли и Матерью Волчицей — на Скалу Совета. Это была вершина холма, усеянная крупными валунами, за которыми могла укрыться целая сотня волков. Акела, большой серый волк-одиночка, избранный вожаком всей Стаи за силу и ловкость, взывал со своей скалы:
— Закон вам известен, закон вам известен! Смотрите же, волки!
Отец Волк вытолкнул на середину круга Лягушонка Маугли. Тот сел на землю, засмеялся и стал играть палочками.
Задачу он придумал себе простую: нужно было из этих палочек сложить прямоугольник максимальной площади — при этом использовать все палочки было не обязательно.
Вход. Первая строка содержит количество палочек . Во второй строке заданы их длины — натуральные числа в диапазоне от до .
Выход. Выведите максимальную площадь прямоугольника, который можно сложить из данного набора палочек, или число , если сложить прямоугольник невозможно.
8 7 1 5 2 3 2 4 5
49
Пусть — данное множество палочек. Необходимо найти два непересекающихся подмножества и из , такие, что палочки каждого из них можно разбить на два подмножества с равной суммой длин.
Для каждого подмножества вычислим сумму длин его палочек и запишем в .
Переберём все подмножества . Для каждого подмножества переберём все его подмножества . Если существует такое , что (то есть суммарная длина палочек в вдвое меньше суммы длин всех палочек из ), то подмножество можно использовать в качестве противоположных сторон прямоугольника. В этом случае установим .
Вся описанная процедура выполняется за .
Переберём все подмножества множества палочек. Если для некоторого множества существует подмножество такое, что и (то есть множества и не пересекаются), то тем самым получаем одно из возможных распределений палочек между горизонтальными и вертикальными сторонами прямоугольника.
Длины сторон такого прямоугольника равны и . Среди всех найденных вариантов выбираем прямоугольник с максимальной площадью.
Длины палочек хранятся в массиве . Для каждого подмножества палочек сохраняем их суммарную длину в массиве . Значение устанавливаем в , если множество можно разделить на два подмножества с равной суммой длин — им будут соответствовать противоположные стороны прямоугольника.
#define MAX 16 int a[MAX]; int sum[1 << MAX]; bool can[1 << MAX];
Основная часть программы. Читаем входные данные.
scanf("%d",&n);
for (i = 0; i < n; i++)
scanf("%d", &a[i]);Переберём все подмножества палочек и вычислим суммарную длину каждого из них.
for (i = 0; i < 1 << n; i++)
for (j = 0; j < n; j++)
if (i & (1 << j)) sum[i] += a[j];Затем переберём все возможные подмножества множества палочек. Если для некоторого множества существует подмножество такое, что суммарная длина палочек в вдвое меньше суммарной длины палочек в , то установим . В этом случае палочки из множества можно использовать как противоположные стороны прямоугольника.
for (i = 1; i < 1 << n; i++)
{
int s = sum[i];
for (j = i; j > 0; j = (j - 1) & i)
if (sum[j] * 2 == s)
{
can[i] = true;
break;
}
}Переберём все подмножества множества палочек. Если для некоторого множества существует подмножество такое, что и , то получаем одно из возможных распределений палочек между горизонтальными и вертикальными сторонами прямоугольника. Длины сторон такого прямоугольника равны и .
res = 0;
for (i = 1; i < 1 << n; i++)
for (j = i; j > 0; j = (j - 1) & i)
if (can[j] && can[i ^ j])
res = max(res, sum[j] / 2 * 1LL * sum[i ^ j] / 2);Выводим площадь найденного прямоугольника максимального размера.
printf("%lld\n",res);Однажды детектив Сайкат расследовал дело об убийстве. На месте преступления он обнаружил лестницу, на каждой ступеньке которой было написано число. Детектив счел это подозрительным и решил запомнить все числа, встреченные на пути. Вскоре он заметил закономерность: для каждого числа на лестнице он записывал сумму всех ранее встреченных чисел, которые были меньше текущего.
Вам необходимо найти сумму всех чисел, записанных детективом в его дневнике.
Вход. Первая строка содержит число — количество тестов. Далее следуют строк. В первой из них указано число — количество ступенек. В следующей строке записаны чисел — значения, нанесенные на ступеньки. Все числа находятся в диапазоне от до .
Выход. Для каждого теста выведите в отдельной строке итоговую сумму.
1 5 1 5 3 6 4
15
Числа, записанные на ступеньках, являются целыми и находятся в диапазоне от до включительно. Построим дерево Фенвика на массиве длины (индексы массива изменяются от до включительно), изначально заполненном нулями.
Каждый раз, когда детектив проходит ступеньку со значением , увеличим на . При этом в дневнике он запишет сумму:
С учетом ограничений на входные данные, все вычисления следует выполнять в -битовом целочисленном типе.
Пример
Смоделируем записи детектива на приведённом примере. Индексация массива начинается с . Числа, записанные детективом, указаны под стрелками.
Сумма чисел, записанных в дневнике детектива, равна
Пусть максимальный размер массива равен . Создадим дерево Фенвика .
#define MAX 1000001 vector<long long> Fenwick;
Функция Summa0_i вычисляет значение суммы .
long long Summma0_i(int i)
{
long long result = 0;
for (; i >= 0; i = (i & (i + 1)) - 1)
result += Fenwick[i];
return result;
}Функция IncElement увеличивает значение элемента: .
void IncElement(int i, int delta)
{
for (; i < MAX; i = (i | (i+1)))
Fenwick[i] += delta;
}Основная часть программы. Читаем входные данные.
scanf("%d",&tests);
while (tests--)
{
scanf("%d",&n);Заполняем массив нулями.
Fenwick.assign(MAX,0);
Искомую сумму, записанную в дневнике детектива, будем подсчитывать в переменной .
sum = 0;
Последовательно обрабатываем числа, записанные на ступеньках.
for (i = 0; i < n; i++)
{Для каждого значения , записанного на ступеньке, увеличиваем на , а также вычисляем сумму всех ранее встреченных чисел, меньших . Эта сумма равна .
scanf("%d",&value);
IncElement(value, value);
sum += Summma0_i(value - 1);
}Выводим сумму всех чисел, записанных в дневнике детектива.
printf("%lld\n",sum);
}Амин и Мурад решили создать игровой сервер "Майнкрафт".
На торжественное открытие сервера они пригласили гостей. Гости живут в разных городах, и при подключении к серверу (в зависимости от их местоположения) будут испытывать определённую задержку (ping). Осознав возможные трудности, Амин и Мурад решили выбрать самое оптимальное место для размещения сервера.
Имеется городов, пронумерованных от до , и двусторонних каналов связи между ними. Подключение к серверу возможно только по этим каналам. С их помощью можно установить соединение между любыми двумя городами. При этом между двумя городами может быть не более одного прямого канала связи, а ни один город не соединён каналом сам с собой. Для каждого канала указана задержка передачи .
Задержкой соединения между каким-либо городом и сервером считается минимально возможная сумма задержек по каналам на пути из этого города до сервера.
Амин и Мурад хотят выбрать такой город для размещения сервера, чтобы суммарная задержка соединений всех гостей была минимальной. Если сервер размещён в том же городе, где живёт гость, то для него задержка считается равной нулю.
Если существует несколько городов с одинаковой минимальной суммарной задержкой, то Амин и Мурад выберут город с наименьшим номером.
Определите город, в котором будет размещён сервер, и какова будет суммарная задержка соединений всех гостей к серверу.
Вход. В первой строке заданы три целых числа — количество городов, количество каналов связи и количество гостей соответственно. Во второй строке записаны различных чисел — номера городов, в которых живут гости.
В каждой из следующих строк даны три целых числа — описание двустороннего канала связи между городами и с задержкой .
Выход. Выведите два целых числа — номер города, в котором будет размещён сервер, и суммарную задержку соединений всех гостей к этому серверу.

5 6 3 1 2 5 1 2 10 1 4 3 2 4 2 2 5 8 3 4 5 3 5 3
2 13
Поскольку , для представления графа воспользуемся списком смежности.
Запустим алгоритм Дейкстры из всех городов, в которых проживают гости. Для каждой вершины вычислим сумму расстояний до всех городов с гостями. Вершина с наименьшей суммой будет оптимальным местом для размещения сервера. Если таких вершин несколько, выбираем ту, у которой наименьший номер.
Отметим, что сервер не обязательно должен находиться в городе, где проживает один из гостей.
Пример
Граф, приведенный в примере, имеет следующий вид:
Запустим алгоритм Дейкстры из вершин, в которых проживают гости: и . Для каждой из этих вершин определим кратчайшие расстояния до всех остальных городов.
Затем для каждой вершины графа найдём сумму расстояний до всех городов с гостями. Минимальная сумма расстояний равна , и она достигается в вершине с наименьшим номером .
Таким образом, сервер следует разместить в городе . Суммарное расстояние от него до городов, где проживают гости, составляет .
Объявим константу бесконечность.
#define INF 0x3F3F3F3F
Структура будет хранить информацию о ребре: вершину , в которую ведёт ребро, и вес этого ребра.
struct edge
{
int node, dist;
edge(int node, int dist) : node(node), dist(dist) {}
};Объявим компаратор для сортировки пар по убыванию значения .
bool operator< (edge a, edge b)
{
return a.dist > b.dist;
}Объявим список смежности для представления графа.
vector<vector<edge> > g;
Функция Dijkstra реализует алгоритм Дейкстры. На вход она принимает граф и начальную вершину . Возвращаемым значением является массив , где содержит кратчайшее расстояние от вершины до вершины .
void Dijkstra(vector<vector<edge> >& g, vector<int>& d, int start)
{
priority_queue<edge> pq;
pq.push(edge(start, 0));
d = vector<int>(n + 1, INF);
d[start] = 0;
while (!pq.empty())
{
edge e = pq.top(); pq.pop();
int v = e.node;
if (e.dist > d[v]) continue;
for (auto e : g[v])
{
int to = e.node;
int cost = e.dist;
if (d[v] + cost < d[to])
{
d[to] = d[v] + cost;
pq.push(edge(to, d[to]));
}
}
}
}Основная часть программы. Читаем входные данные.
scanf("%d %d %d", &n, &m, &k);
c.resize(k);
for (i = 0; i < k; i++)
scanf("%d", &c[i]);Читаем входной взвешенный граф.
g.resize(n + 1);
for (i = 0; i < m; i++)
{
scanf("%d %d %d", &a, &b, &w);
g[a].push_back(edge(b, w));
g[b].push_back(edge(a, w));
}Запускаем алгоритм Дейкстры из городов, в которых проживают гости.
dp.resize(n + 1);
for (i = 0; i < k; i++)
{
Dijkstra(g, dist, c[i]);
for (j = 1; j <= n; j++)
dp[j] += dist[j];
}На данный момент содержит сумму кратчайших расстояний от вершины до всех городов, в которых находятся гости. Остаётся найти минимальное значение среди элементов массива и вывести соответствующий ответ. Переменная хранит наименьший номер вершины, в которой следует разместить сервер.
res = INF;
for (i = 1; i <= n; i++)
{
if (dp[i] < res)
{
res = dp[i];
ptr = i;
}
}Выводим ответ.
printf("%d %d\n", ptr, dp[ptr]);