1 条题解
-
0
#include<bits/stdc++.h> using namespace std; // [1] 全局常量:最大团伙数量限制,适配题目n≤1000的范围 const int MAXN = 1005; // [2] 全局数组:并查集父节点数组,存储每个团伙的父节点编号 int fa[MAXN]; // [3] 全局数组:并查集连通块大小数组,仅根节点的sz值有效,记录对应连通块的团伙数量 int sz[MAXN]; // [4] 全局数组:邻接表,存储每个团伙的直接联系邻居 vector<int> g[MAXN]; // 函数声明 int find(int x); void unite(int x, int y); bool check(int k, int n); // [5] 主函数:程序运行入口 int main() { int n; cin >> n; // [6] 读入犯罪团伙的总数量n // [7] 循环读入每个团伙的邻居信息,构建邻接表 for(int i = 1; i <= n; i++) { int cnt; cin >> cnt; // [8] 读入当前团伙的邻居数量 // [9] 循环读入所有邻居编号,加入邻接表 for(int j = 0; j < cnt; j++) { int neighbor; cin >> neighbor; g[i].push_back(neighbor); } } // [10] 二分查找最小的k:左边界0(不打击任何团伙),右边界n(打击所有团伙) int l = 0, r = n, ans = n; while(l <= r) { int mid = (l + r) / 2; // [11] 计算当前二分的中间值mid,即尝试打击1~mid的团伙 // [12] 调用check函数判断mid是否可行,跳转至该函数完成注释 if(check(mid, n)) { // [25] 回到主函数,mid可行,尝试寻找更小的k ans = mid; // 更新答案为当前mid r = mid - 1; // 右边界左移,尝试更小的k } else { // [26] mid不可行,需要打击更多团伙,左边界右移 l = mid + 1; } } cout << ans << endl; // [27] 输出最小的k值 return 0; // [28] 主函数正常结束 } // [13] 跳转至find函数:带路径压缩,查找节点x所在连通块的根节点 int find(int x) { // [14] 函数参数x:待查找根节点的团伙编号 if(fa[x] != x) { fa[x] = find(fa[x]); // [15] 路径压缩:直接将当前节点指向根节点,优化后续查询效率 } return fa[x]; // [16] 返回找到的根节点 } // [17] find函数注释完成,返回unite函数继续注释 // [18] 跳转至unite函数:按大小合并x和y所在的两个连通块 void unite(int x, int y) { // [19] 函数参数x、y:待合并的两个团伙编号 x = find(x); // [20] 查找x的根节点 y = find(y); // [20] 查找y的根节点 if(x == y) return; // [21] 两团伙已属于同一连通块,无需重复合并 // [22] 按大小合并:将小的连通块合并到大的连通块中,保持树结构平衡 if(sz[x] < sz[y]) swap(x, y); fa[y] = x; sz[x] += sz[y]; // [23] 更新合并后连通块的大小 } // [24] unite函数注释完成,返回check函数继续注释 // [12] 跳转至check函数:检查打击1~k的团伙后,剩余团伙的最大连通块是否≤n/2 bool check(int k, int n) { // [13] 函数参数k:打击的团伙编号上限;n:团伙总数量 // [14] 循环初始化并查集 for(int i = 1; i <= n; i++) { fa[i] = i; // [15] 每个团伙初始独立为一个连通块,父节点设为自身 sz[i] = 1; // [16] 每个连通块的初始大小为1 } // [17] 遍历所有未被打击的团伙,合并符合条件的边 for(int i = k+1; i <= n; i++) { // [18] 遍历当前团伙的所有邻居 for(int j : g[i]) { if(j > k) // [19] 邻居也未被打击,合并两个团伙 { // [20] 调用unite函数合并两个团伙,跳转至该函数完成注释 unite(i, j); } } } // [24] 回到check函数,合并完成,统计最大连通块大小 int max_sz = 0; // [25] 记录剩余团伙的最大连通块大小 // [26] 遍历所有未被打击的团伙,统计最大连通块 for(int i = k+1; i <= n; i++) { if(find(i) == i) // [27] 当前节点是连通块的根节点 { max_sz = max(max_sz, sz[i]); // 更新最大连通块大小 } } return max_sz <= n / 2; // [28] 返回检查结果:最大连通块是否符合要求 } // [29] check函数注释完成,返回主函数继续注释
- 1
信息
- ID
- 1359
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者