2378:給你一棵樹,如果把一個點去掉,則這棵樹將會被分割成若干塊,如果最大的一個連通塊中點的個數不大於N/2,則這個點是符合要求的點,求所有符合要求的點
而1655則是求一個點,把它去掉後,得到的若干連通塊中有個點的個數最大值,這個最大值比任何其他點進行相同操作得到的最大值都大
這兩個題思路都是一樣的
考慮去掉一個點會出現什麼情況:設該點爲點i,則所有以點i的孩子爲根的子樹都將變成獨立的連通塊,另外,原來整棵樹中除去以i爲根的子樹的部分也是另外一個連通塊
那麼,我們對於一個點i,只要記錄兩個值:
1.所有以i的孩子爲根的子樹中,點的個數最大的一個有多少個點
2.以i爲根的子樹中共有多少個點,這樣就能求出除去以i爲根的子樹,還剩下多少個點
然後再枚舉判斷一下就行
2378代碼:(1655的只要改下輸入和枚舉判斷就行)
#include<iostream>
#include<memory.h>
#include<string>
#include<cstdio>
#include<algorithm>
#include<math.h>
#include<stack>
#include<queue>
#include<vector>
#include<map>
using namespace std;
const int MAX=10005;
struct node
{
int v,next;
}g[MAX*5];
int adj[MAX],cnt[MAX],dp[MAX],res[MAX],e;
int n;
void add(int u,int v)
{
g[e].v=v; g[e].next=adj[u]; adj[u]=e++;
}
void dfs(int u,int fa)
{
int i,v;
cnt[u]=1;
dp[u]=0;
for(i=adj[u];i!=-1;i=g[i].next)
{
v=g[i].v;
if(v==fa)
continue;
dfs(v,u);
cnt[u]+=cnt[v];
dp[u]=max(dp[u],cnt[v]);
}
}
int main()
{
int i,j,k;
while(scanf("%d",&n)!=EOF)
{
memset(adj,-1,sizeof(adj));
e=0;
for(i=1;i<n;i++)
{
scanf("%d%d",&j,&k);
add(j,k);
add(k,j);
}
dfs(1,-1);
k=0;
for(i=1;i<=n;i++)
{
if(((n-cnt[i])<=n/2)&&dp[i]<=n/2)
res[k++]=i;
}
if(k==0)
puts("NONE");
else
{
sort(res,res+k);
for(i=0;i<k;i++)
printf("%d\n",res[i]);
//printf("\n");
}
}
return 0;
}