算法知识点: 搜索
复杂度:
解题思路:
由于这道题目的数据较弱,且贪心算法均有反例,因此直接暴搜出所有切割方案,保留最小值即可。
首先预处理出每一层的节点集合,以及每棵子树的大小。
然后从第一层开始,依次枚举每一层中删除哪棵子树,枚举之后通过深度优先遍历,将整棵子树中的边全部标记为不可选,再递归到下一层继续枚举。递归结束时需要再次深度优先遍历整棵子树,将每条边的状态恢复为可选。
当枚举到最后一层时,更新最小值。
暴力枚举过程中需要维护当前已经删除的节点总数。
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;
} 
京公网安备 11010502036488号