1 条题解

  • 0
    @ 2025-6-16 0:43:45

    解题思路

    问题转化:将每个整数视为图中的节点,每对约束条件 (x, y) 视为从 x 到 y 的有向边。目标是找到一个满足拓扑顺序的序列,使得每个节点出现的次数等于给定的计数,并保证字典序最小。 拓扑排序:利用拓扑排序的思想,每次选择入度为 0 的节点,并优先处理数值较小的节点(使用优先队列保证)。 贪心策略:在每个步骤中,尽可能多地添加当前最小的合法数字,确保后续节点仍能满足约束。

    算法原理

    图模型: 节点:每个不同的整数 U(范围 0 到 m-1)。

    边:约束对 (x, y) 表示必须存在从 x 到 y 的路径。

    拓扑排序: 入度:每个节点的入度表示必须出现在它之前的不同节点数量。

    优先队列:使用小顶堆(优先队列)确保每次取出的节点是当前入度为 0 的最小节点。

    合法性检查: 若所有节点的入度最终都被消为 0,说明存在合法序列;否则输出 Impossible!。

    实现步骤

    1.输入处理: 读取整数数量 m 和约束对数 d。 读取每个整数的出现次数 counts。 读取约束对 (x, y)。

    2.图构建: 初始化入度数组 in_degree 和邻接表 graph。 对每个约束对 (x, y),增加 y 的入度,并将 y 添加到 x 的邻接表中。

    3.拓扑排序初始化: 将所有入度为 0 且计数大于 0 的节点加入优先队列。

    4.生成密钥: 从优先队列取出最小节点 u,将其所有出现次数加入结果序列。 减少 u 的所有邻居的入度,若邻居入度变为 0 且计数大于 0,则加入队列。

    5.合法性验证: 检查所有节点的入度是否为 0,若存在非零入度的节点且计数大于 0,说明无解。

    c++代码

    #include <iostream>
    #include <vector>
    #include <queue>
    #include <algorithm>
    #include <map>
    using namespace std;
    
    vector<int> solve(int m, int d, vector<int>& counts, vector<pair<int, int> >& pairs) {
        map<int, int> in_degree;
        map<int, vector<int> > graph;
    
        // Initialize in_degree for all nodes
        for (int i = 0; i < m; ++i) {
            in_degree[i] = 0;
        }
    
        // Build the graph and in_degree
        for (vector<pair<int, int> >::iterator it = pairs.begin(); it != pairs.end(); ++it) {
            int x = it->first;
            int y = it->second;
            graph[x].push_back(y);
            in_degree[y]++;
        }
    
        // Use a priority queue to get the smallest lex order
        priority_queue<int, vector<int>, greater<int> > pq;
    
        // Add nodes with in_degree 0 to the priority queue
        for (int i = 0; i < m; ++i) {
            if (in_degree[i] == 0 && counts[i] > 0) {
                pq.push(i);
            }
        }
    
        vector<int> result;
    
        while (!pq.empty()) {
            int u = pq.top();
            pq.pop();
    
            // Add u to the result as many times as needed
            for (int i = 0; i < counts[u]; ++i) {
                result.push_back(u);
            }
    
            // Decrease in_degree for neighbors
            for (vector<int>::iterator it = graph[u].begin(); it != graph[u].end(); ++it) {
                int v = *it;
                in_degree[v]--;
                if (in_degree[v] == 0 && counts[v] > 0) {
                    pq.push(v);
                }
            }
        }
    
        // Check if all nodes are processed
        for (int i = 0; i < m; ++i) {
            if (counts[i] > 0 && in_degree[i] != 0) {
                return vector<int>();
            }
        }
    
        return result;
    }
    
    int main() {
        int m, d;
        while (cin >> m >> d && (m != 0 || d != 0)) {
            vector<int> counts(m);
            for (int i = 0; i < m; ++i) {
                cin >> counts[i];
            }
    
            vector<pair<int, int> > pairs(d);
            for (int i = 0; i < d; ++i) {
                cin >> pairs[i].first >> pairs[i].second;
            }
    
            vector<int> result = solve(m, d, counts, pairs);
    
            if (result.empty()) {
                cout << "Impossible!" << endl;
            } else {
                for (size_t i = 0; i < result.size(); ++i) {
                    if (i != 0) {
                        cout << " ";
                    }
                    cout << result[i];
                }
                cout << endl;
            }
        }
        return 0;
    }
    • 1

    信息

    ID
    534
    时间
    1000ms
    内存
    256MiB
    难度
    10
    标签
    递交数
    5
    已通过
    1
    上传者