【推導】Codeforces Round #484 (Div. 2) C. Cut 'em all!

題意:給你一棵樹,讓你切掉儘量多的邊,使得產生的全部連通塊都有偶數個結點。spa

對於一棵子樹,若是它有奇數個結點,你再從裏面怎麼摳掉偶數結點的連通塊,它都不會變得合法。若是它原本就有偶數個結點,那麼你怎麼摳,都是合法的。blog

因此,咱們只須要切斷全部有偶數結點的子樹的父邊便可。string

而後再判一遍最後是否還是合法的。io

#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\n",ans);
	return 0;
}
相關文章
相關標籤/搜索