[洛谷]P2018 消息傳遞 (#樹形dp+貪心)

題目描述

巴蜀國的社會等級森嚴,除了國王之外,每個人均有且只有一個直接上級,當然國王沒有上級。如果A是B的上級,B是C的上級,那麼A就是C的上級。絕對不會出現這樣的關係:A是B的上級,B也是A的上級。

最開始的時刻是0,你要做的就是用1單位的時間把一個消息告訴某一個人,讓他們自行散佈消息。在任意一個時間單位中,任何一個已經接到消息的人,都可以把消息告訴他的一個直接上級或者直接下屬。

現在,你想知道:

1.到底需要多長時間,消息才能傳遍整個巴蜀國的所有人?

2.要使消息在傳遞過程中消耗的時間最短,可供選擇的人有那些?

輸入格式

輸入文件的第一行爲一個整數N(N≤1000),表示巴蜀國人的總數,假如人按照1到n編上了號碼,國王的編號是1。第2行到第N行(共N-1行),每一行一個整數,第i行的整數表示編號爲i的人直接上級的編號。

輸出格式

文件輸出共計兩行:

第一行爲一個整數,表示最後一個人接到消息的最早時間。

第二行有若干個數,表示可供選擇人的編號,按照編號從小到大的順序輸出,中間用空格分開。

輸入輸出樣例

輸入 #1複製

8
1
1
3
4
4
4
3

輸出 #1複製

5
3 4 5 6 7

思路

是所有藍題難度的樹形dp當中較簡單的。意思就是你選一個人進行消息傳遞,然後求最少傳遍時間。

由於根不確定,所以要遍歷所有點作爲根。

令dp[i]爲以i爲子樹,消息傳遍節點i的子樹的所有子樹所需的最小時間。dp[i]取決於花費時間最多的那顆子樹,再加上每1秒的傳播時間,所以先告訴需要花費時間長的,再告訴短的,所以:

dp[i]=max(dp[i],dp[son]+i-1)

其中son爲i的子節點,dp[son]+i-1爲傳遞時間。

#include <stdio.h>
#include <iostream>
#include <algorithm>
#include <memory.h>
#define N 1001
#define inf 2e9+7
using namespace std;
int n,dp[N],head[N],cnt,s[N],a[N],minx(inf);
struct node
{
	int nxt,to;
}e[N<<1];
inline void add(int u,int v)
{
	e[++cnt].to=v;
	e[cnt].nxt=head[u];
	head[u]=cnt;
}
inline bool cmp(int a,int b)
{
	return a>b;
}
void dfs(int u,int fa)
{
	int son[N]={};
	int cnt(0);
	register int i;
	for(i=head[u];i;i=e[i].nxt)
	{
		int v(e[i].to);
		if(v==fa) continue;
		dfs(v,u);
		son[++cnt]=dp[v];//
	}
	sort(son+1,son+cnt+1,cmp);//先傳給時間長的 
	for(i=1;i<=cnt;i++)
	{
		dp[u]=max(dp[u],son[i]+i-1);
	}
	dp[u]++;//別忘了1秒的傳遍時間 
}
signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	register int i,j,k;
	cin>>n;
	for(i=2;i<=n;i++)
	{
		int u;
		cin>>u;
		add(u,i);
		add(i,u);
	}
	for(i=1;i<=n;i++)//每個點都可以當一次根節點 
	{
		memset(dp,0,sizeof(dp));
		dfs(i,0);
		minx=min(minx,dp[i]);
		s[i]=dp[i];
	}
	cout<<minx<<endl;
	for(i=1;i<=n;i++)
	{
		if(minx==s[i])
		{
			cout<<i<<' ';
		}
	}cout<<endl;
	return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章