《算法竞赛-训练指南》第一章-1.15_LA 3902

来源:互联网 发布:诺基亚e71软件下载 编辑:程序博客网 时间:2024/06/07 21:02

这道题目我真的有点泪奔了!

写了整整一下午才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;}



原创粉丝点击