[Offer收割]编程练习赛25:偶树的切分

题目2 : 偶树的切分

时间限制: 10000ms
单点时限: 1000ms
内存限制: 256MB

描述

如果一棵树节点数目是偶数,那么就称这棵树是偶树。给定一棵N个节点的偶树(编号1~N),小Hi想知道他最多可以同时切断多少条边,使得剩下的森林中每一个联通分量都是一棵偶树。

例如如下的偶树:

      1   
   / | | \
  2  3 4  5
  |
  6

可以切断1-2之间边使得剩下的每个联通分量都是偶树。

输入

第一行包含一个偶数N。  

以下N-1行每行包含两个整数a和b,表示a和b之间有一条边。  

对于30%的数据,1 ≤ N ≤ 20  

对于100%的数据, 1 ≤ N ≤ 100000

输出

输出最多可以切断的边数。

样例输入
6  
1 2  
3 1  
4 1  
1 5  
6 2
样例输出
1
思路:以某点为根,其子树中节点为偶数的就直接把根和这个子树的边切掉,如果子树节点数为奇数,就继续以子节点为根,对子树进行上述操作。

因为切掉的部分为偶数个节点,剩下的一定也是偶数个节点。所以一直进行dfs就行。

#include<bits/stdc++.h>
using namespace std;
const int MAX=1e6;
int d[MAX],n,v[MAX],ans;
vector<int>e[MAX];
void cla(int k)
{
    v[k]=1;
    d[k]=1;
    for(int i=0;i<e[k].size();i++)
    {
        int nex=e[k][i];
        if(v[nex])continue;
        cla(nex);
        d[k]+=d[nex];
    }
}
void dfs(int k)
{
    v[k]=1;
    for(int i=0;i<e[k].size();i++)
    {
        int nex=e[k][i];
        if(v[nex])continue;
        if(d[nex]%2==0) //子树中节点数为偶数
        {
            ans++;   //切断这条边
            dfs(nex);//继续以nex为根节点,进行操作
        }
        else dfs(nex);//子树节点数为奇数
    }
}
int main()
{
    scanf("%d",&n);
    memset(d,-1,sizeof d);
    for(int i=1;i<n;i++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        e[x].push_back(y);
        e[y].push_back(x);
    }
    memset(v,0,sizeof v);
    cla(1);  //预处理,d[i]表示以i为根节点的子树中的节点数
    memset(v,0,sizeof v);
    ans=0;
    dfs(1);
    cout<<ans<<endl;
    return 0;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值