1 条题解

  • 0
    @ 2026-4-7 21:20:36
    冷知识,这个国王是色批

    虽然只有一种味道,但真的很 鲜~

    葵花籽味

    #include <iostream>
    #include <vector>
    #include <algorithm>
    #include <cstring>
    #include <stack>
    
    using namespace std;
    
    const int MAXN = 4005; // 王子和姑娘总共最多 4000 个点
    
    vector<int> graph[MAXN]; // 残量网络的邻接表
    vector<int> likes[MAXN]; // 原始喜好关系
    int match_girl[MAXN];    // match_girl[i] = 姑娘 i 匹配的王子
    int match_prince[MAXN];  // match_prince[i] = 王子 i 匹配的姑娘
    
    // Tarjan 算法相关变量
    int dfn[MAXN], low[MAXN], belong[MAXN];
    bool instack[MAXN];
    stack<int> st;
    int index_num, scc_count;
    
    void tarjan(int u) {
        dfn[u] = low[u] = ++index_num;
        st.push(u);
        instack[u] = true;
    
        for (int v : graph[u]) {
            if (!dfn[v]) {
                tarjan(v);
                low[u] = min(low[u], low[v]);
            } else if (instack[v]) {
                low[u] = min(low[u], dfn[v]);
            }
        }
    
        if (dfn[u] == low[u]) {
            scc_count++;
            int v;
            do {
                v = st.top();
                st.pop();
                instack[v] = false;
                belong[v] = scc_count;
            } while (v != u);
        }
    }
    
    int main() {
        // 优化输入输出
        ios::sync_with_stdio(false);
        cin.tie(0);
    
        int n;
        cin >> n;
    
        // 1. 读取喜好关系
        for (int i = 1; i <= n; i++) {
            int k;
            cin >> k;
            likes[i].resize(k);
            for (int j = 0; j < k; j++) {
                cin >> likes[i][j];
            }
        }
    
        // 2. 读取初始匹配
        memset(match_girl, -1, sizeof(match_girl));
        memset(match_prince, -1, sizeof(match_prince));
        
        for (int i = 1; i <= n; i++) {
            cin >> match_prince[i];
            match_girl[match_prince[i]] = i;
        }
    
        // 3. 构建残量网络
        // 点 1~n 表示王子,点 n+1~2n 表示姑娘
        // 如果 (u, v) 在匹配中,加边 v+n -> u
        // 如果 (u, v) 不在匹配中,加边 u -> v+n
        for (int u = 1; u <= n; u++) {
            for (int v : likes[u]) {
                if (match_prince[u] == v) {
                    // 匹配边:姑娘 -> 王子
                    graph[v + n].push_back(u);
                } else {
                    // 非匹配边:王子 -> 姑娘
                    graph[u].push_back(v + n);
                }
            }
        }
    
        // 4. 求强连通分量
        memset(dfn, 0, sizeof(dfn));
        memset(low, 0, sizeof(low));
        memset(instack, false, sizeof(instack));
        index_num = 0;
        scc_count = 0;
    
        for (int i = 1; i <= 2 * n; i++) {
            if (!dfn[i]) {
                tarjan(i);
            }
        }
    
        // 5. 判定可行边并输出
        for (int u = 1; u <= n; u++) {
            vector<int> valid_girls;
            
            for (int v : likes[u]) {
                // 判定条件:
                // 1. (u, v) 是匹配边
                // 2. 或者 u 和 v+n 在同一个强连通分量中
                if (match_prince[u] == v || belong[u] == belong[v + n]) {
                    valid_girls.push_back(v);
                }
            }
    
            // 输出
            cout << valid_girls.size();
            sort(valid_girls.begin(), valid_girls.end());
            for (int girl : valid_girls) {
                cout << " " << girl;
            }
            cout << "\n";
        }
    
        return 0;
    }
    
    仅供参考,以实际葵花籽为准

    信息

    ID
    321
    时间
    1000ms
    内存
    128MiB
    难度
    10
    标签
    递交数
    3
    已通过
    1
    上传者