luogu-P2899

題目描述
Farmer John has decided to give each of his cows a cell phone in hopes to encourage their social interaction. This, however, requires him to set up cell phone towers on his N (1 ≤ N ≤ 10,000) pastures (conveniently numbered 1…N) so they can all communicate.

Exactly N-1 pairs of pastures are adjacent, and for any two pastures A and B (1 ≤ A ≤ N; 1 ≤ B ≤ N; A ≠ B) there is a sequence of adjacent pastures such that A is the first pasture in the sequence and B is the last. Farmer John can only place cell phone towers in the pastures, and each tower has enough range to provide service to the pasture it is on and all pastures adjacent to the pasture with the cell tower.

Help him determine the minimum number of towers he must install to provide cell phone service to each pasture.

John想讓他的所有牛用上手機以便相互交流(也是醉了。。。),他需要建立幾座信號塔在N塊草地中。已知與信號塔相鄰的草地能收到信號。給你N-1個草地(A,B)的相鄰關係,問:最少需要建多少個信號塔能實現所有草地都有信號。

輸入格式

  • Line 1: A single integer: N

  • Lines 2…N: Each line specifies a pair of adjacent pastures with two space-separated integers: A and B

輸出格式

  • Line 1: A single integer indicating the minimum number of towers to install

輸入
5
1 3
5 2
4 3
3 5
輸出
2

這個題有兩種方法做,第一個就是貪心求一個最小支配集,第二種就是樹形DP啦(博主太菜了,只知道這兩種做法,有大佬想其他想法的話可以分享一下嗎)。
我們先講一下最小支配集的做法叭,最小支配集就是選擇一個點集,讓不在這個點集中的點都與集合中的點相連,如果這個集合最小,那麼就是最小支配集啦[笑]。這個做法是運用貪心思想,在一棵樹中,如果我們選擇了一個結點,那麼我們就相當於把它的所有兒子結點和它的父親結點都相連了,那麼如果我們要選擇最小的點,我們就要儘量的不去選葉子結點,並且,如果兒子結點沒有相連,那麼就將父親結點加入最小支配集,這樣就可以讓它的兄弟結點和祖父結點也與最小支配集中的點相連了。
代碼:

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int inf=0x3f3f3f3f;
const int maxn = 1e6 + 7;
struct edge
{
	int v, next;
}e[maxn];
int cnt, head[maxn];
void add(int a,int b)
{
	e[++cnt] = edge{b, head[a]};
	head[a] = cnt;
}
int tot, nex[maxn], pre[maxn];
void dfs(int u,int fa)
{
	nex[++tot] = u;
	for (int i = head[u]; i;i=e[i].next){
		int v = e[i].v;
		if(v==fa)
			continue;
		pre[v] = u;
		dfs(v, u);
	}
}
int s[maxn], vis[maxn], ans = 0;
signed main()
{
	int n;
	cin>>n;
	for (int i = 1; i < n;i++){
		int a, b;
		cin >> a >> b;
		add(a, b), add(b, a);
	}
	pre[1] = 1;
	dfs(1, 1);
	for (int i = tot; i > 0;i--){
		if(!vis[nex[i]]){
			if(!s[pre[nex[i]]]){
				s[pre[nex[i]]] = 1;
				vis[pre[nex[i]]] = 1;
				vis[pre[pre[nex[i]]]] = 1;
				ans++;
			}
			vis[nex[i]] = 1;
		}
	}
	cout << ans << endl;
}

現在我們來講講樹形DP的做法,對於每一個點,我們設置三個狀態:

dp[u][0] 選擇u u和u的子樹都有信號
dp[u][1] 不選u 但至少選了一個兒子 即u和u的子樹都有信號 
dp[u][2] 不選u 但選了孫子結點 即u的子樹有信號,但是u沒有信號 

然後就是每個狀態的決策:
如果選擇了u,看一下會有什麼影響,首先,u和u的子樹都已經被覆蓋了,那麼dp[u][0]的值就將所有兒子結點的三個狀態的最小值相加就可以啦。
如果沒有選擇u,但是至少選了u的一個兒子,那麼u和u的子樹都有信號了,那麼對於u這個子樹來說,u的兒子必須被覆蓋,那麼將滿足這個要求的兩個狀態的值的最小值相加就可以啦。
如果不選u,但是選了孫子結點,使得u的子樹都有信號,但是u沒有信號,那麼能夠造成這種現象的情況就是能夠滿足v是u的兒子,v有信號,我們將v的兒子是信號塔的情況相加就可以了。
代碼:

dp[u][0] 選擇u u和u的子樹都有信號
dp[u][1] 不選u 但至少選了一個兒子 即u和u的子樹都有信號 
dp[u][2] 不選u 但選了孫子結點 即u的子樹有信號,但是u沒有信號 
dp[u][0]+=min(max(dp[v][0],dp[v][1]),dp[v][2]);
dp[u][1]=min(dp[v][0] + min(dp[v1][0],dp[v1][1]));
dp[u][2]+=dp[v][1];

然後我們就這樣去更新狀態就可以了。
代碼:

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int inf=0x3f3f3f3f;
const int maxn = 1e6 + 7;
struct edge
{
	int v, next;
}e[maxn];
int cnt, head[maxn];
void add(int a,int b)
{
	e[++cnt] = edge{b, head[a]};
	head[a] = cnt;
}
int dp[maxn][3];
/*
dp[u][0] 選擇u u和u的子樹都有信號
dp[u][1] 不選u 但至少選了一個兒子 即u和u的子樹都有信號 
dp[u][2] 不選u 但選了孫子結點 即u的子樹有信號,但是u沒有信號 
dp[u][0]+=min(max(dp[v][0],dp[v][1]),dp[v][2]);
dp[u][1]=min(dp[v][0] + min(dp[v1][0],dp[v1][1]));
dp[u][2]+=dp[v][1];
*/
void dfs(int u,int fa)
{
	dp[u][0] = 1;dp[u][1]=inf;
	int sum = 0;
	for (int i = head[u]; i;i=e[i].next){
		int v = e[i].v;
		if(v==fa)
			continue;
		dfs(v, u);
		dp[u][0] += min(min(dp[v][0], dp[v][1]), dp[v][2]);
		dp[u][2] += dp[v][1];
		sum += min(dp[v][0], dp[v][1]);
	}
	for (int i = head[u]; i;i=e[i].next){
		int v = e[i].v;
		if(v==fa)
			continue;
		dp[u][1] = min(dp[u][1], sum - min(dp[v][0], dp[v][1]) + dp[v][0]);
	}
}
signed main()
{
	int n;
	cin>>n;
	for (int i = 1; i < n;i++){
		int a, b;
		cin >> a >> b;
		add(a, b), add(b, a);
	}
	
	dfs(1, 1);
	printf("%d\n", min(dp[1][0], dp[1][1]));
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章