您的位置:首页 > 理论基础 > 计算机网络

树(网络,LA 3902)

2016-10-24 15:41 211 查看
可能是因为做了很多树形DP,而很少做其他题的缘故,我总希望通过一遍或几遍DFS来完成预处理以及计算答案。这样的思路是十分狭隘的。一开始想让树的重心或者中心来做根,然后dfs下去,找到一个最上面的点做服务器,使得下面所有叶子都能被照顾到。但是这样的话如何判断这个点以上的叶子是否被照顾到就十分难以解决。而且已有的那个服务器还会带来额外的麻烦。

自己对这种题目的应对实在是太死板了。

有一个值得学习的地方是部分dfs,就是选某个点,然后以他为根,对他进行限制深度的dfs,凡是访问过的地方就标记一个vis,这样就可以实现树的覆盖。每次选一个最深的待覆盖的点,然后在他的k级祖先上放服务器,就可以保证这个祖先的所有待覆盖儿子都能被覆盖到。然后对这个服务器跑一遍部分dfs,就能照顾到祖先以上的点。部分dfs时更新覆盖的点,以便下次再选一个没覆盖的最深的点。

判断某个点有没有被覆盖,只用一个vis数组。

选取最深的待覆盖点,可以用优先队列,也可以像大白书上那样push_back()到代表某个深度的vector里。

至于寻找待覆盖点,只用在一开始以s为根跑一遍dfs,dfs带上深度的参数,把所有深度大于k的叶保存起来就好了。

代码

#include<bits/stdc++.h>
#define maxn 1010
using namespace std;

int n,s,k;
vector<int>MAP[maxn];
vector<int>node[maxn];
int fa[maxn];
bool vis[maxn];

void dfs(int u,int f,int d)
{
fa[u]=f;
if(MAP[u].size()==1&&d>k)
node[d].push_back(u);
for(unsigned int i=0;i<MAP[u].size();i++)
{
int v=MAP[u][i];
if(v==f) continue;
dfs(v,u,d+1);
}
}

void dfs2(int u,int f,int d)
{
if(d>k) return;
vis[u]=true;
for(unsigned int i=0;i<MAP[u].size();i++)
{
int v=MAP[u][i];
if(v==f) continue;
dfs2(v,u,d+1);
}
}

int main()
{
int T;
scanf("%d",&T);
while(T--)
{
memset(vis,0,sizeof(vis));
scanf("%d %d %d",&n,&s,&k);
for(int i=0;i<=n;i++)
{
MAP[i].clear();
node[i].clear();
}
int a,b;
for(int i=1;i<n;i++)
{
scanf("%d %d",&a,&b);
MAP[a].push_back(b);
MAP[b].push_back(a);
}
dfs(s,-1,0);
int ans=0;
for(int i=n-1;i>k;i--)
for(unsigned int j=0;j<node[i].size();j++)
{
int u=node[i][j];
if(!vis[u])
{
ans++;
for(int i=0;i<k;i++) u=fa[u];
dfs2(u,-1,0);
}
}
printf("%d\n",ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: