题解 P2458 [SDOI2006]保安站岗

Posted colazcy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了题解 P2458 [SDOI2006]保安站岗相关的知识,希望对你有一定的参考价值。

题目链接

Solution [SDOI2006]保安站岗

题目大意:给定一棵\(n\)个点的树,每个点可以覆盖与之相连的所有点,求最小点集覆盖所有点。

我们用\(f[u][d]\)表示以\(u\)为根的这棵子树,\(u\)点的覆盖状态为\(d\)时的最小点花费.(\(d = 0\)\(u\)点被父节点覆盖,\(d = 1\)\(u\)点被自己覆盖,\(d = 2\)\(u\)点被子节点覆盖)

那么

\[f[u][0] = \sum_v \in son(u) min(f[v][1],f[v][2])\]

\(f[u][1] = \sum_v \in son(u) min(f[v][0],f[v][1],f[v][2]) + val(x)\)

\(f[u][2] = f[x][1] + \sum_v \in son(u),v \neq x min(f[v][1],f[v][2])\)

关键在于\(f[u][2]\)的处理,\(n^2\)枚举时间爆炸

我们可以预处理一个\(sum = \sum min(f[v][1],f[v][2])\)

然后\(f[u][2] = min\sum - min(f[v][1],f[v][2]) + f[v][1]\\)

代码:

#include <cstdio>
#include <vector>
using namespace std;
const int maxn = 2048;
vector<int> G[maxn];
template <typename T>
inline T min(const T &a,const T &b,const T &c)
    return min(a,min(b,c));

inline void addedge(int from,int to)
    G[from].push_back(to);

int f[maxn][3],val[maxn];
void dfs(int u,int faz)
    int sum = 0;
    f[u][1] = val[u];
    f[u][2] = 0x7fffffff;
    for(int v : G[u])
        if(v != faz)
            dfs(v,u);
            f[u][0] += min(f[v][1],f[v][2]);    
            f[u][1] += min(f[v][0],f[v][1],f[v][2]);
            sum += min(f[v][1],f[v][2]);
        
    for(int v : G[u])
        if(v == faz)continue;
        f[u][2] = min(f[u][2],sum - min(f[v][1],f[v][2]) + f[v][1]);
    

int n,u,m,v;
int main()
    scanf("%d",&n);
    for(int i = 1;i <= n;i++)
        scanf("%d",&u),scanf("%d %d",val + u,&m);
        while(m--)scanf("%d",&v),addedge(u,v),addedge(v,u);
    
    return dfs(1,0),printf("%d\n",min(f[1][1],f[1][2])),0;

以上是关于题解 P2458 [SDOI2006]保安站岗的主要内容,如果未能解决你的问题,请参考以下文章

P2458 [SDOI2006]保安站岗

[Luogu2458][SDOI2006]保安站岗

[luogu 2458][SDOI2006]保安站岗

SDOI2006 保安站岗

[SDOI2006] 保安站岗

保安站岗