//P280树的最大独立集
#include<iostream>
#include<cstring>
#include<Windows.h>
using namespace std;
const int nodemax=6001;
int edge[nodemax][nodemax];
int n;
int dp[nodemax][2]; //0就是不包含自己本身在里面 1就是包含自己本身在里面
bool vis[nodemax];
int p[nodemax];
void input();
int dfs(int num,int in);
void build1(int root, int num); //填表法用的
void build2(int root,int num); //第num个结点的父节点是root
int main(int argc,char * argv[])
{
input();
memset(p, 0, sizeof(p));
p[1] = -1;
//build1(-1,1); //填表法
build2(-1,1); //这个是刷表法用的
cout << max(dp[1][0], dp[1][1]) << endl; //一定要查找根节点的!
//for check 查看dp的结果是不是对的
/*
cout<<"*********************"<<endl;
for(int i=1;i<=n;i++)
cout<<dp[i][0]<<"\t"<<dp[i][1]<<endl;
*/
return 0;
}
void build1(int root, int num)
{
p[num] = root;
dp[num][0] = 0;
dp[num][1] = 1;
for (int i = 1; i <= n; i++)
{
if (edge[num][i] && p[num] != i) //无根树里面相连的要么是父节点 要么是子节点 不可能说自己的子节点和自己的父节点相连 不然会有环 所以只要相连的是父节点 就是往上走 是子节点就是往下走
{
build1(num, i);
dp[num][1]+=dp[i][0];
dp[num][0]+=max(dp[i][0],dp[i][1]);
// nei++;
}
}
}
void build2(int root,int num) //在构建过程中就可以写出来
{
p[num] = root;
dp[num][0] = 0;
dp[num][1] = 1;
int nei = 0;
for (int i = 1; i <= n; i++)
{
if (edge[num][i] && p[num]!=i) //无根树里面相连的要么是父节点 要么是子节点 不可能说自己的子节点和自己的父节点相连 不然会有环 所以只要相连的是父节点 就是往上走 是子节点就是往下走
{
build2(num, i);
nei++;
}
}
if (p[num] > 0)
{
if (nei ) //有子节点
{
dp[p[num]][1] += dp[num][0];
}
//不管有没有子节点 这个是总要更新的
dp[p[num]][0] += max(dp[num][0], dp[num][1]);
}
}
void input()
{
cin>>n;
int begin,end;
memset(edge,0,sizeof(edge));
for(int i=1;i<n;i++)
{
cin>>begin>>end;
edge[begin][end]=1;
edge[end][begin]=1;
}
}