题目:http://poj.org/problem?id=2378
题意:有n个谷仓有n-1条路连接,问最少删除哪几个点才能使得删除点后得到的连通图的加点数不大于n/2.
分析:求树的重心的变形题,poj3107的简单版,一遍dfs从叶子到根转移找出找到以每个节点为根的子树的结点数,f[u]={ f[v1]+f[v2]+.....+f[vn] }+1;使得每棵子树节点数小于n/2,并且父节点得那个连通图节点数小于等于n/2,即n-f[u]<=n/2.
如果没有这样的点,输出NONE,但是一定会有这样的点,为什么?嘿嘿嘿
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<iostream>
#include<vector>
#define INF 0xfffffff
using namespace std;
const int N=10000+5;
struct edge
{
int v,next;
}e[N<<1];
int head[N],f[N];
bool vis[N];
int cnt,n,sum;
vector<int>ans;//可以满足要求的点放在这里面
void init()
{
memset(head,-1,sizeof(head));
memset(f,0,sizeof(f));
memset(vis,0,sizeof(vis));
cnt=1;
sum=n/2;
}
void add_edge(int u,int v)
{
e[cnt].v=v;
e[cnt].next=head[u];
head[u]=cnt++;
}
void dfs(int u)
{
f[u]=1;
vis[u]=1;
bool flag=true;
for(int i=head[u];~i;i=e[i].next){
int v=e[i].v;
if(!vis[v]){
dfs(v);
if(f[v]>sum)flag=false;
f[u]+=f[v];
}
}
if(flag&&n-f[u]<=sum)
ans.push_back(u);
}
int main()
{
int u,v;
//freopen("f.txt","r",stdin);
while(~scanf("%d",&n)){
init();
for(int i=0;i<n-1;i++){
scanf("%d%d",&u,&v);
add_edge(u,v);
add_edge(v,u);
}
dfs(1);
sort(ans.begin(),ans.end());
//if(ans.size()==0)printf("NONE\n");肯定不会输出NONE
for(int i=0;i<ans.size();i++)
printf("%d\n",ans[i]);
}
return 0;
}