树的最小支配集和最小点覆盖

最小支配集

定义1:对于图G=(V,E)来说,最小支配集指的是从V中取尽量少的点组成一个集合,使得对于V中剩余的点都与取出来的点有边相连。也就是说,设V‘是图G的一个支配集,则对于图中的任意一个顶点u,要么属于集合V’,要么与V‘中的顶点相邻。在V’中出去任何元素后V‘不再是支配集,则支配集是极小支配集。称G的所有支配集中顶点个数最少的支配集为最小支配集,最小支配集中顶点的个数称为支配数。

最小点覆盖

定义2:对于图G=(V,E)来说,最小点覆盖指的是从V中取尽量少的点组成一个集合使得E中所有的边都与取出来的点相连。也就是说,设V‘是图G的一个顶点覆盖,则对于图中的任意一条边(u,v),要么u属于集合V’,要么v属于集合V‘。在V‘中除去任何元素后V’不在是顶点覆盖,则V‘是极小顶点覆盖。称G的所有顶点覆盖中顶点个数最少的覆盖为最小点覆盖。

最大独立集

定义3:对于图G=(V,E)来说,最大独立集指的是从V中取尽量多的点组成一个集合,使得这些点之间没有边相连。也就是说,设V’是图G的一个独立集,则对于图中任意一条边(u,v),u和v不能同时属于集合V',甚至可以u和v都不属于集合V‘。在V’中添加任何不属于V‘元素后V’不再是独立集,则V‘是极大独立集。称G的所有顶点独立集中顶点个数最多的独立集为最大独立集。 

Strategic game【树上DP】【树的最小点覆盖】

题解:不取父亲结点,那么必须取儿子节点,这样才能保证父亲和儿子的连边会被覆盖;
取父亲结点,那么儿子节点可取 可不取;
dp[ u ] [ 0 ] += dp [ v ] [ 1 ] ;
dp [ u ] [ 1 ] += min( dp [ v ] [ 1 ] , dp [ v ] [ 0 ] ) ;

#include<bits/stdc++.h>
using namespace std;
#define sc(x) scanf("%d",&x)
#define sl(x) scanf("%lld",&x)
#define ll long long
#define pb push_back
typedef pair<int,int>PII;
const int Max=2e5+5;
const ll INF=1e15+5;
const ll mod=1e9+7;
int h[Max],a[Max];
int dp[Max][3];
vector<int>mp[Max];
void dfs(int fa,int x){
	int tot=0,len=mp[x].size();
	dp[x][1]=1;
	for(int i=0;i<mp[x].size();i++){
		int v=mp[x][i];
		if(fa==v) continue;
		dfs(x,v);
		dp[x][0]+=dp[v][1];
		dp[x][1]+=min(dp[v][0],dp[v][1]);
	}
}
int main(){
	int n;sc(n);
		for(int i=0;i<n-1;i++){
			int u;sc(u);
				int v;sc(v);
				mp[u].pb(v);
				mp[v].pb(u);
		}
		dfs(-1,1);
		cout<<min(dp[1][0],dp[1][1])<<endl;
}

[USACO 2008 Jan G]Cell Phone Network【树上DP】【树的最小支配集】

题意:
John想让他的所有牛用上手机以便相互交流,他需要建立几座信号塔在N块草地中。已知与信号塔相邻的草地能收到信号。给你N-1个草地(A,B)的相邻关系,问:最少需要建多少个信号塔能实现所有草地都有信号。

思路:

树的最小支配集。
定义:
dp[i][0]为这个点本身有观测站,
dp[i][1]为这个点没有观测站,但是父亲有,
dp[i][2]为这个点没有观测站,但是儿子有,
那么结果就是min(dp[i][0],dp[i][2])。

转移:
dp[i][0]=∑min(dp[j][0],dp[j][1],dp[j][2])
dp[i][1]=∑min(dp[j][0],dp[j][2])
dp[i][2]=∑min(dp[j][0],dp[j][2])−min(max(dp[j][0],dp[j][2])−dp[j][2])
注意对于dp[i][2],我们要保证子节点至少有一个有观测站,所以如果选的全部是dp[j][2],那么一定要有一个儿子将dp[j][2]替换成dp[j][0],多出来的部分就是dp[j][0]+dp[j][2],取最小的部分,最后加上。

#include<bits/stdc++.h>
using namespace std;
#define sc(x) scanf("%d",&x)
#define sl(x) scanf("%lld",&x)
#define ll long long
#define pb push_back
typedef pair<int,int>PII;
const int Max=2e5+5;
const ll INF=1e15+5;
const ll mod=1e9+7;
int h[Max],a[Max];
int dp[Max][3];
vector<int>mp[Max];
void dfs(int fa,int x){
	int tot=0,len=mp[x].size();dp[x][0]=1;
	for(int i=0;i<mp[x].size();i++){
		int v=mp[x][i];
		if(fa==v) continue;
		dfs(x,v);
		dp[x][0]+=min(dp[v][0],min(dp[v][1],dp[v][2]));
		dp[x][2]+=min(dp[v][0],dp[v][1]);
		if(dp[v][0]>dp[v][1]&&tot<len-2){
		//至少要保证有一个孩子染色了,并且父亲也连接着这个节点,
        //所以小于len-2
			dp[x][1]+=dp[v][1];
			tot++;
		}else dp[x][1]+=dp[v][0];
	}
	if(mp[x].size()==1&&x!=1) dp[x][1]=Max;
}
int main(){
	int n;sc(n);
	for(int i=0;i<n-1;i++){
		int u,v;
		sc(u);sc(v);
		mp[u].pb(v);
		mp[v].pb(u);
	}
	dfs(-1,1);
	cout<<min(dp[1][0],dp[1][1])<<endl;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

瘾ิۣۖิۣۖิۣۖิꦿ

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值