//poj2378
//这道题目的意思是:给你一棵树
// 求在这棵树中删除某个节点后,各个子树的
// 节点数的和不能超过总节点数的一半,
// dp[i]表示i节点及其子树节点的数之和,
// 那么我们可以通过枚举每个子节点的dp[v]
// 得到删除节点i所得到的各个子块的节点数目
// 特殊的,以i节点为子节点的块应该是n-dp[i];
// 记录每个节点的父节点。
// 比如有5个节点,第3号节点有4,5这两个子节点
// 1是2的父节点,2是3的父节点。则dp[3]=3;
// 第一块:n-dp[3]=2;
// 第二块:dp[4]=1;
// 第三块:dp[5]=1;
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 10008;
struct Edge{
int v;
int next;
}edges[maxn<<1];
int dp[maxn];
int adj[maxn];
int edgenum;
int n;
bool vis[maxn];
int father[maxn];
void addedge(int u,int v){
edges[edgenum].v=v;
edges[edgenum].next=adj[u];
adj[u] = edgenum++;
edges[edgenum].v = u;
edges[edgenum].next=adj[v];
adj[v] = edgenum++;
}
void init(){
memset(adj,-1,sizeof(adj));
memset(dp,0,sizeof(dp));
memset(vis,0,sizeof(vis));
//memset(father,0,sizeof(father));
// for (int i=1;i<=n;i++)
// father[i] = i;
edgenum = 0;
for (int i=1;i<n;i++){
int a,b;
scanf("%d%d",&a,&b);
addedge(a,b);
}
}
void dfs(int u){
dp[u] = 1;
vis[u] = true;
for (int i=adj[u];i!=-1;i=edges[i].next){
int v = edges[i].v;
if (!vis[v]){
father[v]=u;
dfs(v);
dp[u] += dp[v];
}
}
}
void solve(){
dfs(1);
bool flag = false;
for (int i=1;i<=n;i++){
int t;
bool xx = true;
for (int j=adj[i];j!=-1;j=edges[j].next){
int v = edges[j].v;
if (father[i]==v)
t = n - dp[i];
else {
t = dp[v];
}
if (t>n/2){
xx = false;
break;
}
}
if (xx){
flag = true;
printf("%d\n",i);
}
}
if (!flag){
printf("NONE\n");
}
}
int main(){
freopen("G:\\Code\\1.txt","r",stdin);
while(scanf("%d",&n)!=EOF){
init();
solve();
//print();
}
}
poj 2378 Tree Cutting 树状dp
最新推荐文章于 2021-02-14 14:20:00 发布