codeforces 2016-2017 NTUWFTSC I Tree Game

38 篇文章 0 订阅
26 篇文章 0 订阅

Consider the following game about coloring edges in a tree.

You are given a tree. Initially, the color of all edges is white. Let a valid path be a simple path such that all its edges are white, and the two endpoints are leaves in the tree. On each step of this game, you can choose a valid path and paint all its edges black. You cannot stop your game until you cannot find any valid path.

The purpose of this game is to use the minimum number of steps to complete the game. Please find the minimum number of steps for the given tree.

Input

The first line of input contains one integer N indicating the number of nodes in the given tree.

Each of the following N - 1 lines contains two integers x and y indicating that x-th node and y-th node are connected by an edge in the given tree. Nodes are numbered from 1 to N.

  • 2 ≤ N ≤ 105
  • 1 ≤ x, y ≤ N
  • the given graph is a tree
Output

Output one integer: the minimum number of steps required to complete the game on the given tree.

Examples
input
7
1 2
1 3
2 4
2 5
3 6
3 7
output
1
input
9
1 2
1 3
2 4
2 5
3 6
3 7
8 2
9 3
output
3
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

贪心~

对于点u的一个子树,我们把它的多余节点都贪心地在子树内配对完毕,这样,每个子树对于u的贡献不超过2。

我们发现,如果一个子树有两个节点未配对,我们可以只配对其中一个,让另一个没有叶子结点可以配对,这样得到的答案一定最小。

所以我们对于u统计它的贡献为1的子树个数aa和贡献为2的子树个数bb,对于所有aa,我们先配对直到aa<=2,对于所有bb,我们先配对直到bb<=1,剩下的aa与bb配对,其余的作为贡献传递到父亲节点。

当根节点得到的答案==2时,要把这两个点连接起来,ans++。

注意n<=3的情况要特判!


#include<cstdio>
#include<iostream>
using namespace std;

int n,x,y,fi[100001],w[200001],ne[200001],du[100001],cnt,ans;

int read()
{
	int x=0,f=1;char ch=getchar();
	while(ch<'0' || ch>'9') {if(ch=='-') f=-1;ch=getchar();}
	while(ch>='0' && ch<='9') {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
	return x*f; 
}

void add(int u,int v)
{
	w[++cnt]=v;ne[cnt]=fi[u];fi[u]=cnt;du[u]++;
	w[++cnt]=u;ne[cnt]=fi[v];fi[v]=cnt;du[v]++;
}

int dfs(int u,int fa)
{
	if(du[u]==1) return 1;
	int now,aa=0,bb=0;
	for(int i=fi[u];i;i=ne[i])
	  if(w[i]!=fa)
	  {
	  	now=dfs(w[i],u);
	  	if(now==1) aa++;
	  	else if(now==2) bb++;
	  }
	while(aa>2) ans++,aa-=2;
	while(bb>1) ans++,bb-=2;
	while(aa>1 && bb) ans++,aa--,bb--;
	aa+=bb*2;
	return aa<2 ? aa:2;
}

int main()
{
	n=read();
	if(n<=3)
	{
		puts("1");return 0;
	}
	for(int i=1;i<n;i++) x=read(),y=read(),add(x,y);
	for(int i=1;i<=n;i++) if(du[i]>1)
	{
		if(dfs(i,0)==2) ans++;break;
	}
	printf("%d\n",ans);
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值