题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4707
题意:一棵树有n个结点,编号从0到n-1,每条边的距离视为1,求与0号结点距离大于d的结点个数。
思路:题目所给n的范围是<=1e5,根据题意,方法应该为从0号结点开始,暴力搜索出与0号结点距离小于等于d的结点个数cnt,然后输出n-cnt即可。接下来是搜索的实现部分,首先选择是DFS还是BFS,分析发现选择任一种均可。然后是图的存储方法,由于n的规模较大不能使用邻接矩阵(O(n^2),会MLE)存储,所以采用邻接表(O(n+e)即2*n不会MLE)存储。但传统数据结构中的邻接表需要维护指针,实现较为复杂,可以考虑使用STL中的vector代替。
这里需要用到vector的一些方法:
- vector::push_back() 将元素加入到向量
- vector::clear() 将向量清空
- vector::size() 返回向量中元素个数
此外vector也支持下标法检索元素,掌握了这些方法即可熟练使用它作为图的邻接表,省去了自己实现可变长向量的麻烦,且效果很好。 存储问题解决后,BFS或DFS就比较容易实现了,这里仅提供一种BFS的实现方法:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <iostream>
#include <algorithm>
#include <vector>
#include <stack>
#include <queue>
using namespace std;
#define MAXN 100010
vector<int> mp[MAXN];
bool vis[MAXN];
int n, d, cnt;
void init(){
for(int i=0; i<MAXN; i++) mp[i].clear();
memset(vis, false, sizeof vis);
cnt = 0;
}
struct NODE{
int id;
int step;
};
void bfs(){
queue<NODE> Q;
NODE st;
st.id = st.step = 0;
vis[0] = true;
cnt++;
Q.push(st);
while(!Q.empty()){
NODE now = Q.front();
Q.pop();
if(now.step > d) break; //剪枝
printf("***to node %d\n", now.id);
int len = mp[now.id].size();
for(int i=0; i<len; i++){
if(vis[mp[now.id][i]] == false){
vis[mp[now.id][i]] = true;
NODE next;
next.id = mp[now.id][i];
next.step = now.step + 1;
Q.push(next);
if(next.step <= d) cnt++;
}
}
}
}
int main()
{
int T, x, y;
cin >> T;
while(T--){
init();
scanf("%d %d", &n, &d);
for(int i=0; i<n-1; i++){
scanf("%d%d", &x, &y);
mp[x].push_back(y);
mp[y].push_back(x);
}
bfs();
printf("%d\n", n - cnt);
}
return 0;
}