[洛谷]P3047 [USACO12FEB]附近的牛Nearby Cows (#樹形dp)

題目描述

Farmer John has noticed that his cows often move between nearby fields. Taking this into account, he wants to plant enough grass in each of his fields not only for the cows situated initially in that field, but also for cows visiting from nearby fields.

Specifically, FJ's farm consists of N fields (1 <= N <= 100,000), where some pairs of fields are connected with bi-directional trails (N-1 of them in total). FJ has designed the farm so that between any two fields i and j, there is a unique path made up of trails connecting between i and j. Field i is home to C(i) cows, although cows sometimes move to a different field by crossing up to K trails (1 <= K <= 20).

FJ wants to plant enough grass in each field i to feed the maximum number of cows, M(i), that could possibly end up in that field -- that is, the number of cows that can potentially reach field i by following at most K trails. Given the structure of FJ's farm and the value of C(i) for each field i, please help FJ compute M(i) for every field i.

農民約翰已經注意到他的奶牛經常在附近的田野之間移動。考慮到這一點,他想在每一塊土地上種上足夠的草,不僅是爲了最初在這片土地上的奶牛,而且是爲了從附近的田地裏去喫草的奶牛。

具體來說,FJ的農場由N塊田野構成(1 <= n <= 100,000),每兩塊田野之間有一條無向邊連接(總共n-1條邊)。FJ設計了農場,任何兩個田野i和j之間,有且只有一條路徑連接i和j。第 i塊田野是C(i)頭牛的住所,儘管奶牛們有時會通過k條路到達其他不同的田野(1<=k<=20)。

FJ想在每塊田野上種上夠M(i)頭奶牛喫的草。M(i)指能從其他點經過最多k步就能到達這個點的奶牛的個數。

現給出FJ的每一個田野的奶牛的數目,請幫助FJ計算每一塊田野的M(i)。

輸入格式

* Line 1: Two space-separated integers, N and K.

* Lines 2..N: Each line contains two space-separated integers, i and j (1 <= i,j <= N) indicating that fields i and j are directly connected by a trail.

* Lines N+1..2N: Line N+i contains the integer C(i). (0 <= C(i) <= 1000)

第一行:n和k;

後面n-1行:i和j(兩塊田野);

之後n行:1..n每一塊的C(i);

輸出格式

* Lines 1..N: Line i should contain the value of M(i).

n行:每行M(i);//i:1..2

輸入輸出樣例

輸入 #1複製

6 2 
5 1 
3 6 
2 4 
2 1 
3 2 
1 
2 
3 
4 
5 
6 

輸出 #1複製

15 
21 
16 
10 
8 
11 

說明/提示

There are 6 fields, with trails connecting (5,1), (3,6), (2,4), (2,1), and (3,2). Field i has C(i) = i cows.

Field 1 has M(1) = 15 cows within a distance of 2 trails, etc.

題目簡述:給出一棵n個點的樹,每個點上有C_i頭牛,問每個點k步範圍內各有多少頭牛。

感謝@Slager_Z 提供翻譯


思路

給出一棵n個點的樹,每個點上有Ci頭牛,問每個點k步範圍內各有多少頭牛。

令dp[i][j]爲節點i向外走j步能覆蓋的奶牛數目。對於這題而言,顯然是個樹形dp,而我們的一般處理方法是在節點i的子樹中合併。然而這題不一樣,答案不只是從子樹中轉移過來,所以最後一定能得到最後2個關於dp[i][j]的方程:

1.從兒子到父親;

2.從父親到兒子。

1.從兒子到父親

顯然地,

dp[i][j]=Σdp[k][j-1]

其中k是i的子節點。轉移很簡單,一個dfs搞定的事情。

2.從父親到兒子

dp[k][j]=Σdp[i][j-1]

其中i是k的父節點。也可以dfs遍歷一遍。

如果真的按照那個方程去寫的話,你會發現只有第1個是對的,剩下的總是多一點,應該是有重複了。因爲到節點i的距離爲2的點包含到節點k距離爲1的節點k的兒子們,那麼重算的一部分應該是dp[i][j-2]。所以要減去。

即最後的方程爲:

dp[i][j]=Σdp[k][j-1]

dp[k][j]=Σdp[i][j-1]-dp[i][j-2]

#include <stdio.h>
#include <iostream>
#define N 100001
using namespace std;
int n,m,cnt,head[N],f[N],dp[N][21],s;
struct node
{
	int to,nxt;
}e[N<<1];
inline void add(int u,int v)
{
	e[++cnt].to=v;
	e[cnt].nxt=head[u];
	head[u]=cnt;
}
void dfs(int u,int fa)
{
	register int i,j;
	for(i=head[u];i;i=e[i].nxt)
	{
		int v(e[i].to);
		if(v==fa) continue;
		dfs(v,u);
		for(j=1;j<=m;j++)
		{
			dp[u][j]+=dp[v][j-1];
		}
	}
}
void dfs1(int u,int fa)
{
	register int i,j;
	for(i=head[u];i;i=e[i].nxt)
	{
		int v(e[i].to);
		if(v==fa) continue;
		/*dp[v][1]+=dp[u][0];
		for(j=2;j<=m;j++)
		{
			dp[v][j]+=dp[u][j-1]-dp[v][j-2];
		}*/
		for(j=m;j>=2;j--)
		{
			dp[v][j]+=dp[u][j-1]-dp[v][j-2];
		}
		dp[v][1]+=dp[u][0];
		dfs1(v,u);
	}
}
signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	register int i,j,k;
	cin>>n>>m;
	for(i=1;i<n;i++)
	{
		int u,v;
		cin>>u>>v;
		add(u,v);
		add(v,u);
	}
	for(i=1;i<=n;i++)
	{
		cin>>dp[i][0];
	}
	dfs(1,0);
	dfs1(1,0);
	for(i=1;i<=n;i++)
	{
		s=0;
		for(j=0;j<=m;j++)
		{
			s+=dp[i][j];
		}
		cout<<s<<endl;
	}
	return 0;
}

 

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