这道题目我真的有点泪奔了!
写了整整一下午才A掉,这是一道比较考察综合知识的题目,要求你对DFS,要求你对模型的建立,要求你对图的掌握要非常熟练。如果是不熟练的话,你是写不出来的。
这个题目的意思是,给你N个结点,代表着客户端和服务端,客户端仅为这个无根树的叶结点时,其余的就是服务端了,但是有一个是发射信号的最终客户端,就要求着,如果有客户端距离服务端太远(距离超过所要求的K)的话,就无法正确的接受到信号了,所以就要重新再建立一个服务端了。题目要求求出需要建立的最少的服务端。
做题的步骤应该是这样的:首先将无根树转化成有根树,无根树转化成有根数的算法就是DFS,将所有的结点搜到,搜索的时候一定要记住要把结点的关系转化成功,也就是,将结点和结点所对应的父亲存好。
这个过程中, DFS能得意进行下去的条件也是至关重要的。if (v != f)也就是不能让他回搜。形成循环,所有的这样双向图都应该是这样判断的。
(中间啊有个小插曲,就是我突然就想看看自己到底打字用几个手指头了,才用了七个,还有三个没有用到啊)
这个还有个很好的知识点,就是将所有待解决的结点,按照深度的不同另外存储起来,然后遍历所有的可能的深度,就可以求出解,当然求可能的时候要求最优解。也就是求距离叶结点最大可满足距离的那个结点。然后循着这个结点DFS所有的叶子结点,标记就行了。
非常的不好意思,为了看自己到底使用几个手指头打字,我发现现在自己都不能好好的打字了,所有有点写的言不达意,很抱歉啊。
贴出代码,我要适应一下正确的打字方法:
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <vector>
#include <string>
using namespace std;
const int MAXN = 1022;
int N;
int root;
int K;
int a, b;
vector <int> G[MAXN], node[MAXN];
int father[MAXN];
int vis[MAXN];
void converse(int v, int f, int d)
{
father[v] = f;
int cnt = G[v].size();
if (d > K && cnt == 1) //如果这个服务器已经覆盖不到了,而且也是个叶子节点,那么先把它存起来.
{
node[d].push_back(v);
}
for (int i = 0; i < cnt; i++)
{
int t = G[v][i];
if (t != f) //这里是t!=f????我要去死!!!
{
converse(t, v, d + 1);
}
}
}
void DFS(int v, int f, int d)
{
if (d > K)
{
return ;
}
int nc = G[v].size();
if (nc == 1 && d <= K)
{
vis[v] = 1;
return ;
}
for (int i = 0; i < nc; i++)
{
int t = G[v][i];
if (t != f)
{
DFS(t, v, d + 1);
}
}
}
/*
void DFS(int u, int f, int d)
{
vis[u] = 1;
int nc = G[u].size();
for (int i = 0; i < nc; i++)
{
int v = G[u][i];
if (v != f && d < K)
{
DFS(v, u, d + 1);
}
}
}
*/
int solve()
{
int cnt = 0;
memset(vis, 0, sizeof(vis));
for (int i = N - 1; i > K; i--)
{
int nc = node[i].size(); //遍历那些没有覆盖的点,从深处开始.
for (int j = 0; j < nc; j++)
{
int v = node[i][j];
if (!vis[v])
{
for (int k = 0; k < K; k++)
{
v = father[v];
}
DFS(v, -1, 0);
cnt++;
}
}
}
return cnt;
}
void init()
{
memset(father, 0, sizeof(father));
for (int i = 1; i <= N; i++) //我都想死了!!!!这初始化!!!~~~我真!!
{
G[i].clear();
node[i].clear();
}
}
int main()
{
int T;
scanf("%d", &T);
while (T--)
{
scanf("%d", &N);
scanf("%d%d", &root, &K);
init();
for (int i = 0; i < (N - 1); i++) //这里使用的是邻接表建图,因为数据量实在是不小1000;
{
scanf("%d%d", &a, &b);
G[a].push_back(b);
G[b].push_back(a);
}
converse(root, -1, 0);
int ans = solve();
printf("%d\n", ans);
}
// system("pause");
return 0;
}