제출 #1306666

#제출 시각아이디문제언어결과실행 시간메모리
1306666tntPolitical Development (BOI17_politicaldevelopment)C++20
100 / 100
298 ms9784 KiB
#include <iostream>
#include <vector>
#include <algorithm>
#include <unordered_set>
#include <set>

using namespace std;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int N, K;
    if (!(cin >> N >> K)) return 0;

    vector<vector<int>> adj(N);
    vector<int> degree(N);
    for (int i = 0; i < N; ++i) {
        int d;
        cin >> d;
        degree[i] = d;
        for (int j = 0; j < d; ++j) {
            int neighbor;
            cin >> neighbor;
            adj[i].push_back(neighbor);
        }
    }

    // 1. Находим порядок вырожденности
    vector<int> order;
    vector<int> current_degree = degree;
    vector<bool> deleted(N, false);
    
    // Используем set для симуляции очереди с приоритетами по степени
    set<pair<int, int>> pq;
    for (int i = 0; i < N; ++i) {
        pq.insert({current_degree[i], i});
    }

    vector<vector<int>> forward_adj(N);

    while (!pq.empty()) {
        int v = pq.begin()->second;
        pq.erase(pq.begin());
        deleted[v] = true;
        order.push_back(v);

        for (int neighbor : adj[v]) {
            if (!deleted[neighbor]) {
                pq.erase({current_degree[neighbor], neighbor});
                current_degree[neighbor]--;
                pq.insert({current_degree[neighbor], neighbor});
                // Сохраняем только те ребра, которые идут "вперед" по порядку
                forward_adj[v].push_back(neighbor);
            }
        }
    }

    // Для быстрой проверки существования ребра (O(log K))
    for (int i = 0; i < N; ++i) {
        sort(adj[i].begin(), adj[i].end());
    }

    auto has_edge = [&](int u, int v) {
        return binary_search(adj[u].begin(), adj[u].end(), v);
    };

    int max_clique = 1;

    // 2. Перебор клик для каждой вершины
    for (int v : order) {
        const auto& neighbors = forward_adj[v];
        int m = neighbors.size();
        
        // Перебираем все подмножества соседей (их не более 2^(K-1))
        for (int mask = 0; mask < (1 << m); ++mask) {
            vector<int> subset;
            for (int i = 0; i < m; ++i) {
                if ((mask >> i) & 1) {
                    subset.push_back(neighbors[i]);
                }
            }

            if (subset.size() + 1 <= max_clique) continue;

            // Проверяем, образует ли подмножество клику
            bool is_clique = true;
            for (int i = 0; i < subset.size(); ++i) {
                for (int j = i + 1; j < subset.size(); ++j) {
                    if (!has_edge(subset[i], subset[j])) {
                        is_clique = false;
                        break;
                    }
                }
                if (!is_clique) break;
            }

            if (is_clique) {
                max_clique = max(max_clique, (int)subset.size() + 1);
            }
        }
    }

    cout << max_clique << endl;

    return 0;
}
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...