算法知识点: 搜索
复杂度:
解题思路:
由于这道题目的数据较弱,且贪心算法均有反例,因此直接暴搜出所有切割方案,保留最小值即可。
首先预处理出每一层的节点集合,以及每棵子树的大小。
然后从第一层开始,依次枚举每一层中删除哪棵子树,枚举之后通过深度优先遍历,将整棵子树中的边全部标记为不可选,再递归到下一层继续枚举。递归结束时需要再次深度优先遍历整棵子树,将每条边的状态恢复为可选。
当枚举到最后一层时,更新最小值。
暴力枚举过程中需要维护当前已经删除的节点总数。
C++ 代码:
#include <cstring> #include <iostream> #include <algorithm> #include <vector> using namespace std; const int N = 310, M = 610; int n, m; int h[N], e[M], ne[M], c[M], idx; int size[N]; vector<int> level[N]; int ans = N, max_depth; void add(int a, int b) { e[idx] = b, ne[idx] = h[a], h[a] = idx++; } int dfs_level(int u, int depth, int father) { size[u] = 1; max_depth = max(max_depth, depth); for (int i = h[u]; ~i; i = ne[i]) { int j = e[i]; if (j != father) { level[depth].push_back(i); size[u] += dfs_level(j, depth + 1, u); } } return size[u]; } void dfs_draw(int i, bool color) { c[i] = color; for (int j = h[e[i]]; j != -1; j = ne[j]) if (j != (i ^ 1)) dfs_draw(j, color); } void dfs(int u, int s) { ans = min(ans, n - s); if (u == max_depth) return; for (auto i: level[u]) if (!c[i]) { dfs_draw(i, true); dfs(u + 1, s + size[e[i]]); dfs_draw(i, false); } } int main() { memset(h, -1, sizeof h); scanf("%d%d", &n, &m); for (int i = 0; i < m; i++) { int a, b; scanf("%d%d", &a, &b); add(a, b), add(b, a); } dfs_level(1, 0, -1); dfs(0, 0); cout << ans << endl; return 0; }