1 条题解

  • 0
    @ 2025-10-27 21:29:17

    题目分析

    这是一个二分图最大独立集问题:选择最多的学生,使得任意一对男女学生之间没有跳过舞。


    关键结论

    对于二分图:

    最大独立集=n最大匹配数\text{最大独立集} = n - \text{最大匹配数}

    算法步骤

    1. 二分图构建

    • 通过 DFS 染色将学生分为两个集合(男生和女生)
    • 颜色标记为 2233,对应二分图的两部

    2. 建立边关系

    • 从颜色 22 的节点向颜色 33 的相邻节点建边
    • 形成二分图的单向边关系

    3. 匈牙利算法求最大匹配

    • 对颜色 22 的每个节点尝试匹配
    • hug(u, ver) 函数实现增广路查找

    4. 计算答案

    • 最大独立集大小 = n最大匹配数n - \text{最大匹配数}

    代码解析

    #include <bits/stdc++.h>
    using namespace std;
    const int N = 1e3 + 10, M = 2e3 + 10;
    
    struct Edge {
        int to, nxt;
    };
    Edge edge[N * N];
    int head[N], en;
    
    void addEdge(int u, int v) {
        edge[++en] = {v, head[u]};
        head[u] = en;
    }
    
    int n, m;
    int c[N], match[N], vis[N];
    
    // DFS 染色构建二分图
    void dfs(int u, int fc) {
        c[u] = fc ^ 1;  // 交替染色
        for (int v : e[u]) {
            if (c[v]) continue;
            dfs(v, c[u]);
        }
    }
    
    // 匈牙利算法匹配
    bool hug(int u, int ver) {
        for (int i = head[u]; i; i = edge[i].nxt) {
            int v = edge[i].to;
            if (vis[v] == ver) continue;
            vis[v] = ver;
            if (!match[v] || hug(match[v], ver)) {
                match[v] = u;
                return true;
            }
        }
        return false;
    }
    
    vector<int> e[N];
    
    int main() {
        scanf("%d%d", &n, &m);
        
        // 读入边关系
        while (m--) {
            int u, v;
            scanf("%d%d", &u, &v);
            u++, v++;  // 调整为1-indexed
            e[u].push_back(v);
            e[v].push_back(u);
        }
        
        // DFS 染色分两部
        for (int i = 1; i <= n; i++)
            if (!c[i]) dfs(i, 3);
        
        // 建立二分图边(从颜色2指向颜色3)
        for (int i = 1; i <= n; i++)
            if (c[i] == 2)
                for (int v : e[i])
                    addEdge(i, v);
        
        // 匈牙利算法求最大匹配
        int ans = 0;
        for (int i = 1; i <= n; i++)
            if (c[i] == 2 && hug(i, i))
                ans++;
        
        printf("%d\n", n - ans);
        return 0;
    }
    

    染色策略

    • 初始颜色设为 33 (fc=3)
    • c[u] = fc ^ 1 产生交替颜色 2233
    • 最终形成二分图的两部:颜色 22 和颜色 33

    匈牙利算法细节

    • vis[v] = ver:使用时间戳优化,避免每次清空 vis 数组
    • hug(match[v], ver):递归尝试重新安排匹配

    复杂度分析

    • 时间复杂度O(n×m)O(n \times m)
    • 空间复杂度O(n+m)O(n + m)

    n1000n \leq 1000m2000m \leq 2000 时完全可行。


    样例验证

    样例 1

    • n=8n = 8,最大匹配 =3= 3
    • 答案 =83=5= 8 - 3 = 5

    样例 2

    • n=20n = 20,最大匹配 =4= 4
    • 答案 =204=16= 20 - 4 = 16

    该解法通过二分图建模和匈牙利算法,高效求解了最大独立集问题。

    • 1

    信息

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