http://poj.org/problem?id=3107
给定一棵树,取去掉某一节点后形成子树的最大节点数,求使这个数最小的节点。
去掉某一节点后,形成的树包括子树和原树去掉以这个点为根的树所形成的树,在这几个树中求最大值即可。
节点数的计算可用回溯,过程中选取最大值。
貌似是我第一个用邻接表存边的题,贴下模板。
邻接表存边code:
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
const int nMax=1000;
class edge{
public:
int v,nex;
};edge e[nMax];
int n,k,head[nMax]; //head[i]是以点i为起点的链表头部
void addedge(int a,int b){//向图中加有向边的算法,注意加上的是有向边
//b为a的后续节点既是a---->b
e[k].v=b;
e[k].nex=head[a];
head[a]=k;
k++;
}
int main(){
int i,a,b,w,k=1;
scanf("%d",&n);
memset(head,0,sizeof(head));
for(i=0;i<n;i++){
scanf("%d%d",&a,&b);
addedge(a,b); //添加一条由a指向b的边
}
cin>>w; //输出w点所指向的点
for(i=head[w];i;i=e[i].nex){
cout<<e[i].v<<endl;
}
cout<<"end\n";
return 0;}
#include<cstring>
#include<cstdio>
using namespace std;
const int nMax=1000;
class edge{
public:
int v,nex;
};edge e[nMax];
int n,k,head[nMax]; //head[i]是以点i为起点的链表头部
void addedge(int a,int b){//向图中加有向边的算法,注意加上的是有向边
//b为a的后续节点既是a---->b
e[k].v=b;
e[k].nex=head[a];
head[a]=k;
k++;
}
int main(){
int i,a,b,w,k=1;
scanf("%d",&n);
memset(head,0,sizeof(head));
for(i=0;i<n;i++){
scanf("%d%d",&a,&b);
addedge(a,b); //添加一条由a指向b的边
}
cin>>w; //输出w点所指向的点
for(i=head[w];i;i=e[i].nex){
cout<<e[i].v<<endl;
}
cout<<"end\n";
return 0;}
code:
#include<cstdio>
#include<cstring>
#include<algorithm>
#define Max(a, b) a>b?a:b
using namespace std ;
const int MAX = 50001 ;
int vis[MAX], head[MAX], ans[MAX], num[MAX] ;
int n, k, Min, sum ;
struct Edge{
int v, next ;
}edge[2*MAX] ;
void addedge(int a, int b){
edge[k].v = b ;
edge[k].next = head[a] ;
head[a] = k ++ ;
}
void dfs(int x){
int i, v, min = -1 ;
num[x] = 1 ;
vis[x] = 1 ;
for(i=head[x]; i; i=edge[i].next){
v = edge[i].v ;
if(vis[v]) continue ;
dfs(v) ;
num[x] += num[v] ;//计算节点数
min = Max(min, num[v]) ;//选取子树中节点最多的
}
min = Max(min, n-num[x]) ;//子树中较大者与除去root为x的树相比较
if(min<Min){
Min = min ;
sum = 1 ;
ans[0] = x ;
}else if(min==Min){
ans[sum++] = x ;
}
}
int main(){
int x, y ;
scanf("%d", &n) ;
k = 1 ;
memset(head, 0, sizeof(head)) ;
for(int i=1; i<n; i++){
scanf("%d%d", &x, &y) ;
addedge(x, y) ;
addedge(y, x) ;
}
memset(num, 0, sizeof(num)) ;
memset(vis, 0, sizeof(vis)) ;
Min = MAX ;
dfs(1) ;
sort(ans, ans+sum) ;
for(int i=0; i<sum; i++)
printf("%d ", ans[i]) ;
printf("\n") ;
return 0 ;}
#include<cstring>
#include<algorithm>
#define Max(a, b) a>b?a:b
using namespace std ;
const int MAX = 50001 ;
int vis[MAX], head[MAX], ans[MAX], num[MAX] ;
int n, k, Min, sum ;
struct Edge{
int v, next ;
}edge[2*MAX] ;
void addedge(int a, int b){
edge[k].v = b ;
edge[k].next = head[a] ;
head[a] = k ++ ;
}
void dfs(int x){
int i, v, min = -1 ;
num[x] = 1 ;
vis[x] = 1 ;
for(i=head[x]; i; i=edge[i].next){
v = edge[i].v ;
if(vis[v]) continue ;
dfs(v) ;
num[x] += num[v] ;//计算节点数
min = Max(min, num[v]) ;//选取子树中节点最多的
}
min = Max(min, n-num[x]) ;//子树中较大者与除去root为x的树相比较
if(min<Min){
Min = min ;
sum = 1 ;
ans[0] = x ;
}else if(min==Min){
ans[sum++] = x ;
}
}
int main(){
int x, y ;
scanf("%d", &n) ;
k = 1 ;
memset(head, 0, sizeof(head)) ;
for(int i=1; i<n; i++){
scanf("%d%d", &x, &y) ;
addedge(x, y) ;
addedge(y, x) ;
}
memset(num, 0, sizeof(num)) ;
memset(vis, 0, sizeof(vis)) ;
Min = MAX ;
dfs(1) ;
sort(ans, ans+sum) ;
for(int i=0; i<sum; i++)
printf("%d ", ans[i]) ;
printf("\n") ;
return 0 ;}