题 意:输入包含n个点的无向图,问删除其中一个点,是否能使剩下的图,每个图中所包含的点均小于n/2。求所有满足要求的点,并按从小到大的顺序排队。
数据范围:
1<=n<=1000
样例输入:
10
1 2
2 3
3 4
4 5
6 7
7 8
8 9
9 10
3 8
样例输出:
3
8
思 路:我们需要维护每一个点切割后,所产生的块中所包含的点最大d[u]是多少,它包括切割该点后,改点个分支孩子节点,父亲节点。
那么怎么维护呢?首先建树,dfs建树。其实在建树的同时就可以维护,当前节点包含的子节点个数,以及d[u],维护当前节点所包含的节点数看
codeforce-1006E
关键点,其实这题可以分析出这么写的。也就是建树。维护d[u]
收获:学习了怎么dfs建树,加深了对dfs的理解 学习了怎么维护各分支子节点以及父节点的最大值.
刘汝佳建树模板
vector<int>G[MAXN];
int father[MAXN];//记录i结点的父亲是谁、
void read_tree(){ //读入
int u,v;
scanf("%d",&n);
for(int i=1; i<n; ++i){
scanf("%d%d",&u,&v);
G[u].push_back(v);
G[v].push_back(u);
}
}
//转化过程、
void dfs(int u, int fa){ //递归转化为以u为根的子树,u的父节点为fa
int d = G[u].size(); //结点u的相邻点个数、
for(int i=0; i<d; ++i){
int v = G[u][i]; //提取u的相邻点
if(v!=fa) dfs(v, father[v] = u); //把v的父节点设为u,然后递归转化为以v为根节点的子树
}
}
AC代码
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<vector>
using namespace std;
const int INF = 0x3f3f3f3f;
const int maxn = 1e4+5;
vector<int>G[maxn];
int father[maxn];
int d[maxn];
int n;
//这是一段比较好的代码
int dfs(int u,int v){
int sum = 1,mson = 0;
d[u] = 0;
for(int i=0;i<G[u].size();i++){ //维护个分支子节点和父节的最大值
int to = G[u][i];
if(to == v)continue;
int ans = dfs(to,father[to] = u);
mson = max(mson,ans);
sum += ans;
}
d[u] = max(mson,n-sum);
return sum; //只需要传递当前节点的子节点的个数就好
}
int main() {
while(~scanf("%d",&n)){
memset(d,0,sizeof(d));
for(int i=0;i<maxn;i++)G[i].clear();
int s,t;
for(int i=2;i<=n;i++){
scanf("%d %d",&s,&t);
G[s].push_back(t);
G[t].push_back(s);
}
dfs(1,0);
for(int i=1;i<=n;i++){
if(d[i]*2 <= n){
printf("%d\n",i);
}
}
}
return 0;
}