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]));
}
发布了34 篇原创文章 · 获赞 3 · 访问量 228

猜你喜欢

转载自blog.csdn.net/qq_44641782/article/details/103869158
今日推荐