题意:将一棵树(不一定是二叉树)分割成每部分的大小都是K的子树,看看是否能够分割成功,成功输出YES,不成功输出NO
由于分割成子树处理,可以遐想到递归的处理,分割一个树,先去分割他的子树,再分割子树的子树...本题如果从自顶而下做比较困难,使用深度优先处理(dfs),可以递归到子树再开始处理。
递归到最小子树,就开始返回,他的值-》一直到返回到最初的dfs,再返回到main函数
题目中的题意告诉我们是否能分割成多个大小为K的子树,
所以某一个子树的子树+它本身>K,就说明本题的答案已经是NO了,直接return-1即可
而在子树返回的数==K时,我们已经知道这个子树可以被分割成一个符合题意的子树了,就不用再计数这棵树,直接当成不存在就好了,所以直接+0
返回数小于k的时候,说明这棵树的总结点数还没有到达要求,我们让他继续加下去
可以得到一个基本模板
ANS=1;
for(一棵树的多个子树编号)
{
int t=弹出的子树编号;
if(子树编号==现在这棵树的母结点)
continue; //直接跳过
//now表示现在的子树编号
int z=dfs(弹出的子树编号,now);
if(z<K); //z<K不管他
if(z==K) z=0; //z=k,让他为0
if(z==-1||z>k)
return -1; //返回-1,表示这个树已经不能被分割成题意了
ANS+=z; //ANS表示现在这棵树的节点个数(包括它本身)
}
return ANS;
以下是源代码
#include <iostream>
#include <vector> //动态数组用来存储,防止空间浪费
using namespace std;
//int s[100005]; //存储树的数组
int N; //结点数
int K; //连通块大小
vector<int> s[100005]; //存储树的数组
int ans[10] = { 0 };
int dfs(int now, int last)
{
int ANS = 1;
for (int i = 0;i < s[now].size();i++) //链表中所有的点
{
int t = s[now][i]; //弹出的第i个结点
if (t == last)
continue; //是母结点,直接跳过
int k = dfs(t, now);
/*k<K 继续加
k==k 让k变回为0
k>K 返回-1*/
if (k == K) k = 0;
if (k == -1||k>K) return -1;
ANS += k;
}
return ANS;
}
int main()
{
int t,v1,v2,i=0;
cin >> t;
int j = t;
while (t--)
{
cin >> N >> K;
for (int i = 0;i <= N ;i++)
s[i].clear();
for (int i = 0;i < N - 1;i++)
{
cin >> v1 >> v2;
s[v1].push_back(v2); //存入子结点
s[v2].push_back(v1); //存入母结点(本题没有用处,但其他题求路径用得到)
}
ans[i] = dfs(1, 1);
if (ans[i] == -1 || ans[i] > K) ans[i] = 0;
else ans[i] = 1;
i++;
}
for (int i = 0;i < j;i++)
if (ans[i] == 0)
cout << "NO" << endl;
else
cout << "YES" << endl;
return 0;
}