「一本通 5.2 例 5」皇宫看守题解

题目描述

太平王世子事件后,陆小凤成了皇上特聘的御前一品侍卫。

皇宫以午门为起点,直到后宫嫔妃们的寝宫,呈一棵树的形状,某些宫殿间可以互相望见。大内保卫森严,三步一岗,五步一哨,每个宫殿都要有人全天候看守,在不同的宫殿安排看守所需的费用不同。

可是陆小凤手上的经费不足,无论如何也没法在每个宫殿都安置留守侍卫。

帮助陆小凤布置侍卫,在看守全部宫殿的前提下,使得花费的经费最少。

Picture1

思路:

做过最大独立集,最小点覆盖,这次终于写到了最小支配集。

最小支配集是选择最少的点去覆盖所有的点,每个选择的点可以覆盖相连的点和它本身。

dp方程:

1.f[pos][0]=min(f[v][0],f[v][2]);

2.f[pos][1]+=min(f[v][0],f[v][2]);
3.f[pos][2]+=min(f[v][0],min(f[v][1],f[v][2]));

1. 可以监控T的子树     不放本身结点
2. 可以不监控T的子树    不放本身结点
3. 可以监控T的子树      放本身结点

所以说第一种情况需要讨论,如果存在f[v][2]被选,就不需要管,因为可以保证pos被v覆盖.

如果没有f[v][2]被选,就需要在abs(f[v][0]-f[v][2])中选一个最小值,

来选.

还有这道题的输入不能搞错....

代码:

#include<bits/stdc++.h>
#define ll long long 
#define R register
using namespace std;
const int N=1e5+85;
struct E{
  int nxt,to;
}e[N];
int n,num,head[N],rot[N],val[N],root=1,f[N][3];
inline void add(R int u,R int v){
    e[++num].to=v;
    e[num].nxt=head[u];
    head[u]=num;
}
// 监控T的子树   不放0  
// 可以不监控    不放1
// 监控T的子树   放 2
inline void dp(R int pos,R int fa){
     f[pos][2]=val[pos];
     R int pd=1,vis=1,cha=0x3f3f3f3f;
     for(R int i=head[pos];i;i=e[i].nxt){
        R int v=e[i].to;
        if(v!=fa){
        pd=0;
        dp(v,pos);
        if(f[v][0]>=f[v][2]){
        f[pos][0]+=f[v][2];
        vis=0;
        }
        else{
        f[pos][0]+=f[v][0];
        cha=min(cha,f[v][2]-f[v][0]);
        }
        f[pos][1]+=min(f[v][0],f[v][2]);
        f[pos][2]+=min(f[v][0],min(f[v][1],f[v][2]));
        }
    }
    if(vis&&pd==0)
    f[pos][0]+=cha;
      if(pd){
    f[pos][0]=val[pos];
    f[pos][1]=0;
    f[pos][2]=val[pos];
    }
}
int main(){
    scanf("%d",&n);
    for(R int i=1;i<=n;++i){
        R int p,m,w;
        scanf("%d%d%d",&p,&w,&m);
        val[p]=w;
        for(R int j=1;j<=m;++j){
           R int k;
           scanf("%d",&k);
           add(k,p);add(p,k);
           rot[k]=1;
        }
    }
    while(rot[root])root++;
    dp(root,0);
    printf("%d",min(f[root][0],f[root][2]));
    return 0;
}
原文地址:https://www.cnblogs.com/sky-zxz/p/9851914.html