решение4

advertisement
Разбор.
Описанная в условии задачи структура партии представляет собой дерево. Пусть для
некоторого его поддерева справедливо следующее: каждая ветвь данного поддерева в отдельности
содержит менее K элементов, а все поддерево в целом - K или более элементов (число элементов в
поддереве равно сумме элементов в его ветвях плюс один элемент, соответствующий корневой
вершине поддерева). Тогда очевидно, что удаление корневой вершины данного поддерева (то есть
арест соответствующего члена партии) решает поставленную задачу в рамках рассмотренного
поддерева оптимальным образом.
Действительно, удаление вершин, не принадлежащих данному поддереву, не может уменьшить
избыточное число элементов в нашем поддереве, а удаление иной вершины поддерева, кроме
корневой, возможно, и приведет к решению задачи для рассмотренного поддерева, но тогда
непосредственный "начальник" не удаленной корневой вершины "идеологически обезвреженного"
поддерева будет иметь по крайней мере на одного "подчиненного" больше, что может увеличить
общее число удалений вершин (арестов).
В результате получаем следующий алгоритм решения задачи. Начиная с "листовых" вершин
(соответствующих рядовым членам партии, не имеющим подчиненных), подсчитываем для
каждой вершины дерева количество элементов в связанном с ней поддереве. Если количество
элементов в поддереве оказалось больше или равно K, то его корневая вершина удаляется, данное
поддерево исключается из рассмотрения и задача решается для оставшихся элементов дерева.
Последним из рассмотренных элементов должна оказаться вершина № 1, обозначающая лидера
партии. Так, в приведенном примере данный алгоритм предложит удалить вершины дерева с
номерами 7, 6, 2 и 1. Алгоритм является линейным относительно количества членов партии, а его
реализация зависит от выбора структуры данных для хранения исходного дерева.
Считать количество членов партии с главарем (корневой вершиной) i будем рекурсивно
(динамически). Принцип подсчета основан на рекурсивной реализации обхода в глубину, только
при просмотре соседей (подчиненных в данной задаче) вершины, мы будем рекурсивно
запрашивать количество членов партии, с корнем в этом соседе. Если количество больше или
равно К, то возвращаем 0. Таким образом суммируются количества всех соседей и записывается в
основную вершину. И так далее. Начинаем обход с первой вершины. После его завершения
пробежимся по массиву количеств, если 0 – то выводим на экран (то есть мы удалили поддерево с
корнем в этой вершине).
Решение на С++:
#include <iostream>
#include <stack>
#include <list>
using namespace std;
int n, k;
list<int> mass[10000]; // массив списков
int cols[10000];
//массив количеств подчиненных
int col = 0;
//количество удаленных
//рекурсивная процедура вычисления количества членов
//в партии с главой в вводимой вершине
int GetCol(int v)
{
if (mass[v].size() == 0)//если вершина не имеет подчиенных
1
{
cols[v] = 1;
return 1;
//то партия состоит из 1-го члена
}
else
{
int ans = 0;
//обнуляем ответ для данной вершины
list<int>::iterator iter = mass[v].begin();
while (iter != mass[v].end()) //пробегаем по всем подчиненным
{
ans+= GetCol(*iter);
//и увеличиваем ответ на количество
iter++;
// членов в партии подчиненного
}
if (ans + 1 >= k)
// если оказалось, что членов больше К
{
col++;
//то удаляем эту партию
cols[v] = 0;
// и возвращаем 0
return 0;
}
cols[v] = ans+1;
return ans + 1;
}
}
int main()
{
freopen("input.txt", "r", stdin);
cin >> k >> n;
cols[0] = 0;
for (int i = 1; i < n; ++i)
{
cols[i] = 0;
int to;
cin >> to;
to--;
mass[to].push_back(i);
}
GetCol(0);
cout << col << endl;
for (int i = 0; i < n; ++i)
if (cols[i] == 0)
cout << i+1 << " ";
return 0;
}
2
Download