1. 程式人生 > >AtCoder-3912 E - Antennas on Tree

AtCoder-3912 E - Antennas on Tree

參考部落格:https://blog.csdn.net/whzzt/article/details/79321484

核心思想大概是對於一個點u,他所有的連線的點所在的連通塊中最多有一個連通塊中沒有選擇的點。

如果有2個以上的話,那麼其他連通塊通過u點到達那兩個連通塊上的點dis會出現一樣的。

補充一蛤,為什麼是O(n)呢,因為從葉子節點找到第一個度>=3的點,中間經過的點必定是一條鏈,而這條鏈上的點只經過一次,所以所有葉子節點dfs找到一個度>=3的點,這中間的路徑上的點不會重複,所以為O(n),就算整棵樹都是鏈也就是2*n

此題也可以樹形DP做,不過直接利用這個結論更方便

#include<bits/stdc++.h>
#define maxl 100010

using namespace std;

int n,ans,cnt;
int ehead[maxl];
int du[maxl];
struct ed
{
	int to,nxt;
}e[maxl<<1];
bool vis[maxl];

inline void add(int u,int v)
{
	e[++cnt].to=v;e[cnt].nxt=ehead[u];ehead[u]=cnt;
}

inline void prework()
{
	for(int i=1;i<=n;i++)
		vis[i]=false,ehead[i]=0,du[i]=0;
	int u,v;
	cnt=0;
	for(int i=1;i<n;i++)
	{
		scanf("%d%d",&u,&v);
		u++;v++;
		add(u,v);du[v]++;
		add(v,u);du[u]++;
	}
}

inline int dfs(int u,int fa)
{
	int v;
	for(int i=ehead[u];i;i=e[i].nxt)
	{
		v=e[i].to;
		if(v==fa) continue;
		if(du[v]>2)
			return v;
		else
			return dfs(v,u);
	}
}

inline void mainwork()
{
	bool flag=true;
	for(int i=1;i<=n;i++)
	if(du[i]>2)
		flag=false;
	if(flag)
	{
		ans=1;
		return;
	}
	ans=0;
	for(int i=1;i<=n;i++)
	if(du[i]==1)
		vis[dfs(i,0)]=true,ans++;
	for(int i=1;i<=n;i++)
	if(vis[i])
		ans--;
}

inline void print()
{
	printf("%d\n",ans);
}

int main()
{
	while(~scanf("%d",&n))
	{
		prework();
		mainwork();
		print();
	}
	return 0;
}