luogu P2458 [SDOI2006]保安站岗

显而易见

树形dp

然而我做了很很很很很久

最后看讨论版才de出来bug

要考虑三个状态

1.父节点有保安

2.本身有保安

3.儿子节点放保安

1.2.douhenhaokaolv

3.不太容易,看了题解才有思路

dp[u][2]:点u没有放置警察,且目前未被任何节点控制。

所以u一定会被它的至少一个儿子控制,换句话来说,u的儿子中,至少有一个要放置警察。不妨设这个儿子为x,那么dp[u][2]的初始值应当为dp[x][0],对于其它儿子依旧是除了无法选择被父亲控制这种状态其它都可以选。综上dp[u][2]=dp[x][0]+∑v∈son(u)≠xmin(dp[v][0],dp[v][2])

那么现在的问题就是如何得到这个最优的x了,可以这么思考,如果x不是最优的,那么对于x来说,一定存在另一个子节点y满足 dp[y][0]+∑v∈son(u)≠ymin(dp[v][0],dp[v][2])<dp[x][0]+∑v∈son(u)≠xmin(dp[v][0],dp[v][2])

推得dp[x][0]+∑v∈son(u)≠xmin(dp[v][0],dp[v][2])?dp[y][0]?∑v∈son(u)≠ymin(dp[v][0],dp[v][2])>0

两式同时减去相同的部分,有dp[x][0]+min(dp[y][0],dp[y][2])?dp[y][0]?min(dp[x][0],dp[x][2])>0

即dp[x][0]?min(dp[x][0],dp[x][2])>dp[y][0]?min(dp[y][0],dp[y][2])

所以对于最优的节点x,dp[x][0]?min(dp[x][0],dp[x][2])一定是所有子节点中最小的

写完之后一直90分

会WA掉第三个点

讨论版中友情提示

这题的数据有毒,说一下几个坑.

  1. 可能不连通,但是不要管,直接以1为根,只算以1为根的联通块的答案就好.
  2. 数据范围和描述不一致,都当成正常的N=1e5,M=2e5的"无向图就好了".
  3. 数据格式有问题,给出的不一定是父亲连向儿子的边,直接建成无向的,dfs的时候判一下v!= fa就好了

然后存了双向边就过了。。。emmm

#include<cstdio>
#include<algorithm>
using namespace std;
#define maxn 1510

int head[maxn],cnt;
int du[maxn];
int v[maxn];
int dp[maxn][3];

struct EDGE {
    int nxt,to;
} edge[maxn * 2];

void add(int x,int y) {
    edge[++cnt].to = y;
    edge[cnt].nxt = head[x];
    head[x] = cnt;
}

void treedp(int u,int fa) {
    int x = 0;
    dp[u][0] = v[u];
    for(int i = head[u]; i; i = edge[i].nxt) {
        int v = edge[i].to;
        if(v == fa)
        continue;
        treedp(v,u);
        dp[u][0] += min(dp[v][0],min(dp[v][1],dp[v][2]));
//本身放了保安
        dp[u][1] += min(dp[v][0],dp[v][2]);
//父节点放了保安
        if((dp[x][0] - min(dp[x][0],dp[x][2])) > dp[v][0] - min(dp[v][0],dp[v][2]))
            x = v;
//子节点放保安
//        dp[u][1] += min(dp[v][0],dp[v][1]);
//        minn = min(minn,dp[v][1]);
//        printf("dp[%d][1] = %d    dp[%d][0] = %d\n",u,dp[u][1],u,dp[u][0]);
    }
    dp[u][2] = dp[x][0];
    for(int i = head[u]; i; i = edge[i].nxt) {
        int v = edge[i].to;
        if(v == x)
        continue;
        dp[u][2] += min(dp[v][0],dp[v][2]);
    }
}

int main() {
    int n;
    scanf("%d",&n);
    dp[0][0] = 1 << 30;//初始化避免被选
    while(n--) {
        int i,k,m;
        scanf("%d%d%d",&i,&k,&m);
        v[i] = k;
        while(m--) {
            int r;
            scanf("%d",&r);
            add(i,r);
            add(r,i);//村双向
            du[r]++;
            //    printf("orz %d\n",du[i]);
        }
    }
//    for(int i = 1; i <= n; i++)
//        printf("orz %d\n",du[i]);
    int root = 1;
    for(int i =1; i <= n; i++)
        if(du[i] == 0) {
            root = i;
            break;
        }//似乎把1当成根就可以了
//    printf("qwq %d\n",root);
    treedp(root,0);
    printf("%d",min(dp[root][0],dp[root][2]));//根节点没有父节点
    return 0;
}

原文地址:https://www.cnblogs.com/sevenyuanluo/p/10352847.html

时间: 2024-07-31 04:28:29

luogu P2458 [SDOI2006]保安站岗的相关文章

[luogu 2458][SDOI2006]保安站岗

题目描述 五一来临,某地下超市为了便于疏通和指挥密集的人员和车辆,以免造成超市内的混乱和拥挤,准备临时从外单位调用部分保安来维持交通秩序. 已知整个地下超市的所有通道呈一棵树的形状:某些通道之间可以互相望见.总经理要求所有通道的每个端点(树的顶点)都要有人全天候看守,在不同的通道端点安排保安所需的费用不同. 一个保安一旦站在某个通道的其中一个端点,那么他除了能看守住他所站的那个端点,也能看到这个通道的另一个端点,所以一个保安可能同时能看守住多个端点(树的结点),因此没有必要在每个通道的端点都安排

P2458 [SDOI2006]保安站岗

没注意放置时还有权值还行 #include<bits/stdc++.h> using namespace std; int n,val[150000],m,ne,a,b,head[150000],f[150000][3]; struct node{int nxt,to;}eg[150000]; void adde(int u,int v){eg[++ne].nxt=head[u];eg[ne].to=v;head[u]=ne;} void dfs(int u,int fa) { int sum

题解 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[

[Luogu2458][SDOI2006]保安站岗

题目描述 五一来临,某地下超市为了便于疏通和指挥密集的人员和车辆,以免造成超市内的混乱和拥挤,准备临时从外单位调用部分保安来维持交通秩序. 已知整个地下超市的所有通道呈一棵树的形状:某些通道之间可以互相望见.总经理要求所有通道的每个端点(树的顶点)都要有人全天候看守,在不同的通道端点安排保安所需的费用不同. 一个保安一旦站在某个通道的其中一个端点,那么他除了能看守住他所站的那个端点,也能看到这个通道的另一个端点,所以一个保安可能同时能看守住多个端点(树的结点),因此没有必要在每个通道的端点都安排

SDOI 2006 - 保安站岗

最小点费用覆盖,即选中费用最小的i个点把所有的边覆盖. #include <cstdio> using namespace std; #define MAXV 1505 #define MAXE (MAXV - 1) int Vefw[MAXE], Veh[MAXV], Vet[MAXE], Vc[MAXV], Veptr; int dp[MAXV][3],dp2[MAXV]; #define min(a,b) ((a)<(b)?(a):(b)) #define addedge(s,t)

【luogu P2455 [SDOI2006]线性方程组】 题解

题目链接:https://www.luogu.org/problemnew/show/P2455 嗯...在消元过程中不要直接拿矩阵元素自己消,会把自己消成0. 1 #include <algorithm> 2 #include <cstdio> 3 #include <cmath> 4 #include <iostream> 5 using namespace std; 6 const int maxn = 200; 7 const double eps

保安站岗

分析: 树形dp刚刚入门,这是我做的第一个一个点同时受父亲节点和儿子节点控制的题目. 由于这个题中某一个点放不放保安与父亲和儿子都有关系(因为线段的两个端点嘛),所以我们做题时就要考虑全面. 假设dp数组为f[i][j]f[i][j]:其中f[i][0]f[i][0]表示选择自己(本身这个点),f[i][1]f[i][1]表示自己不选,儿子选(不选本身这个点,而选择这个点的儿子节点),f[i][2]f[i][2]表示自己不选,父亲选(不选本身这个点而选择这个点的父亲节点) 有点啰嗦... 看了我

树形dp 入门

今天学了树形dp,发现树形dp就是入门难一些,于是好心的我便立志要发一篇树形dp入门的博客了. 树形dp的概念什么的,相信大家都已经明白,这里就不再多说.直接上例题. 一.常规树形DP P1352 没有上司的舞会 题目描述 某大学有N个职员,编号为1~N.他们之间有从属关系,也就是说他们的关系就像一棵以校长为根的树,父结点就是子结点的直接上司.现在有个周年庆宴会,宴会每邀请来一个职员都会增加一定的快乐指数Ri,但是呢,如果某个职员的上司来参加舞会了,那么这个职员就无论如何也不肯来参加舞会了.所以

C++的常用输入及其优化以及注意事项

$P.S:$ 对于输入方式及其优化有了解的大佬可直接阅读$Part$ $2$ 特别鸣谢:@归斋目录: $Part$ $1$                                                        读入方式们的万年争斗 $Part$ $2$                                                        读入不谨慎,爆0两行泪 $Part$ $1$ 读入方式们的万年争斗 有一些$OIer$很喜欢用$cin$,多方便