最小支配集
定义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;
}