题意:给你一棵树,让你切掉尽可能多的边,使得产生的所有连通块都有偶数个结点。
对于一棵子树,如果它有奇数个结点,你再从里面怎么抠掉偶数结点的连通块,它都不会变得合法。如果它本来就有偶数个结点,那么你怎么抠,都是合法的。
所以,我们只需要切断所有有偶数结点的子树的父边即可。
然后再判一遍最后是否仍是合法的。
#include<cstdio> #include<cstring> using namespace std; int n; int e,first[100005],nex[200005],v[200005]; void AddEdge(int U,int V){ v[e]=V; nex[e]=first[U]; first[U]=e++; } bool vis[100005]; bool cut[200005]; int siz[100005]; int ans; void dfs(int U,int kara){ siz[U]=1; vis[U]=1; for(int i=first[U];i!=-1;i=nex[i]){ if(!vis[v[i]]){ dfs(v[i],i); siz[U]+=siz[v[i]]; } } if(kara!=-1 && siz[U]%2==0){ cut[kara]=cut[kara^1]=1; ++ans; } } int cnt; void df2(int U){ vis[U]=1; ++cnt; for(int i=first[U];i!=-1;i=nex[i]){ if(!vis[v[i]] && !cut[i]){ df2(v[i]); } } } int main(){ memset(first,-1,sizeof(first)); scanf("%d",&n); int x,y; for(int i=1;i<n;++i){ scanf("%d%d",&x,&y); AddEdge(x,y); AddEdge(y,x); } dfs(1,-1); memset(vis,0,sizeof(vis)); for(int i=1;i<=n;++i){ if(!vis[i]){ cnt=0; df2(i); if(cnt%2==1){ puts("-1"); return 0; } } } printf("%d ",ans); return 0; }