1 条题解
-
0
题目分析
这是一个二分图最大独立集问题:选择最多的学生,使得任意一对男女学生之间没有跳过舞。
关键结论
对于二分图:
算法步骤
1. 二分图构建
- 通过 DFS 染色将学生分为两个集合(男生和女生)
- 颜色标记为 和 ,对应二分图的两部
2. 建立边关系
- 从颜色 的节点向颜色 的相邻节点建边
- 形成二分图的单向边关系
3. 匈牙利算法求最大匹配
- 对颜色 的每个节点尝试匹配
hug(u, ver)函数实现增广路查找
4. 计算答案
- 最大独立集大小 =
代码解析
#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; }
染色策略
- 初始颜色设为 (
fc=3) c[u] = fc ^ 1产生交替颜色 和- 最终形成二分图的两部:颜色 和颜色
匈牙利算法细节
vis[v] = ver:使用时间戳优化,避免每次清空 vis 数组hug(match[v], ver):递归尝试重新安排匹配
复杂度分析
- 时间复杂度:
- 空间复杂度:
在 , 时完全可行。
样例验证
样例 1:
- ,最大匹配
- 答案 ✓
样例 2:
- ,最大匹配
- 答案 ✓
该解法通过二分图建模和匈牙利算法,高效求解了最大独立集问题。
- 1
信息
- ID
- 4311
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者