51nod 1378:夾克老爺的憤怒 很好玩的一道樹狀dp

基準時間限制:1 秒 空間限制:131072 KB 分值: 80 難度:5級算法題
 收藏
 取消關注
夾克老爺逢三抽一之後,由於採用了新師爺的策略,鄉民們叫苦不堪,開始組織起來暴力抗租。
夾克老爺很憤怒,他決定派家丁常駐村中進行鎮壓。
諾德縣 有N個村莊,編號0 至 N-1,這些村莊之間用N - 1條道路連接起來。
家丁都是經過系統訓練的暴力機器,每名家丁可以被派駐在一個村莊,並鎮壓當前村莊以及距離該村莊不超過K段道路的村莊。
夾克老爺一貫奉行最小成本最大利潤的原則,請問要實現對全部村莊的武力控制,夾克老爺需要派出最少多少名家丁?

Input
第1行:2個數N, K中間用空格分隔(1<= N <= 100000, 0 <= K <= N)。
之後N-1行:每行2個數S, E中間用空格分隔,表示編號爲S的村莊同編號爲E的村莊之間有道路相連。(0 <= S, E < N)。
Output
輸出一個數說明要實現對全部村莊的武力控制,夾克老爺需要派出最少多少名家丁?
Input示例
4 1
0 1
0 2
0 3
Output示例
1

官方題解:樹形DP,貪心思想,從葉子節點向上,能不放就不放,到了k長就放一個。
後序遍歷,記錄不同子樹上傳的狀態,子樹狀態記錄爲該子樹可以向上管理的(缺少的用負數)
可能A子樹放置的家丁可以把B子樹的村莊全部覆蓋,這樣就可以節約家丁數了。
min_length = min(dp[child])
max_length = max(dp[child])
if(min_length <= -K) {
    ++result;
    dp[cur_idx] = K;   //子樹需要暴力支援深度達到K了,必須在當前位置放置一個家丁,並向上提供K的暴力輸出
} else if(max_length + min_length > 0) {
    dp[cur_idx] = max_child - 1;      //有一個子樹放置的家丁能夠把全部其他需要鎮壓的村莊都覆蓋
} else {
    dp[cur_idx] = min_child - 1;      //繼續向上級要求暴力支持
}

最後如果root的狀態小於0要額外多放一個。


這個題目真的挺好玩的,把這n個村莊n-1個連接想象成是一個樹,然後記錄每一個節點缺少的級別,當到達了k個級別的時候就要加上一個家丁,此時這個節點缺少的級別是正的k,因爲它要開始照顧到它的兄弟子樹了。

手動擴棧擴棧也是頭一次。。。

代碼:

#pragma comment(linker, "/STACK:1024000000,1024000000")  
#include <iostream>  
#include <algorithm>  
#include <cmath>  
#include <vector>  
#include <string>  
#include <cstring>  
#pragma warning(disable:4996)  
using namespace std;

#define inf 0x3f3f3f3f

int res;
int n, k;
int s, e; 
int used[100050];
int dp[100050];
vector<int>node[100050];

void dfs(int x)
{
	used[x] = 1;
	int minn = inf;
	int maxn = -inf;
	int size = node[x].size();

	int i;
	for (i = 0; i < size; i++)
	{
		int temp = node[x][i];
		if (used[temp] == 0)
		{
			dfs(temp);
			minn = min(minn, dp[temp]);
			maxn = max(maxn, dp[temp]);
		}
	}
	if (minn == inf)
	{
		dp[x] = -1;
	}
	else if(minn<=-k)
	{
		res++;
		dp[x] = k;
	}
	else if (maxn + minn > 0)
	{
		dp[x] = maxn - 1;
	}
	else
	{
		dp[x] = minn - 1;
	}
	used[x] = 0;
}

int main()
{
	//freopen("i.txt", "r", stdin);
	//freopen("o.txt", "w", stdout);
	
	int i;
	scanf("%d%d", &n, &k);
	
	for (i = 1; i <= n - 1; i++)
	{
		scanf("%d%d", &s, &e);
		s++;
		e++;
		node[s].push_back(e);
		node[e].push_back(s);
	}
	if (k == 0)
	{
		printf("%d", n);
		return 0;
	}
	dfs(1);

	if (dp[1] < 0)
	{
		res++;
	}
	printf("%d", res);
	//system("pause");
	return 0;
}


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