其他分享
首页 > 其他分享> > $Luogu$ $P2016$ 战略游戏

$Luogu$ $P2016$ 战略游戏

作者:互联网

链接

背景

\(2000-2001\) \(Southeastern\) \(European\) \(Regional\) \(Programming\) \(Contest\) ( \(ICPC\) \(SEERC\) \(2000\) ) \(A\) 题弱化版, \(Luogu\) \(P2016\)

题意

以节点、儿子个数及其儿子集合的形式给出一棵 \(n\) 个点的无根树(点从 \(0\) 标号至 \(n-1\) ),规定一个节点可以覆盖距离它不超过 \(1\) 的所有节点,求全图能被覆盖住要使用的最少点数。

解法

又是树形\(dp\)模板。
自然地,设 \(f_{x,0/1}\) 表示 \(x\) 节点不使用和使用时覆盖以 \(x\) 为根的子树的最小代价。
问题来了,给定的树没根,咋办?(话说这个傻逼问题足足困扰了我二十分钟。。。。。。)
只要随便选个根就是有根树啦!
为了方便,不妨设 \(1\) 号节点为根,则直接从 \(1\) 号点开始 \(dfs\) 出所有点的父亲即可。
现在回到转移上来。设边集为 \(E\) ,自然地,有 \(f_{x,0}=\sum_\limits{(x,y) \in E} f_{y,1},f_{x_1}=\sum_\limits{(x,y) \in E} \min \{ f_{y,0},f_{y,1} \}+1\) 。那么要求的就是 \(\min \{f_{1,0},f_{1,1} \}\) 。

细节

由于给定的点是 \([0,n-1]\) 内的,考虑读入的时候统一 \(+1\) 移至正整数区间内再做。

代码

\(View\) \(Code\)

#include<bits/stdc++.h>
using namespace std;
inline int read()
{
    int ret=0,f=1;
    char ch=getchar();
    while('9'<ch||ch<'0')
    {
        if(ch=='-')
            f=-1;
        ch=getchar();
    }
    while('0'<=ch&&ch<='9')
    {
        ret=(ret<<1)+(ret<<3)+ch-'0';
        ch=getchar();
    }
    return ret*f;
}
int n,x,y,cnt,fa[1505],f[1505][2];
int num,head[300005];
bool vis[1505];
struct edge
{
    int ver,nxt;
}e[300005];
inline void adde(int u,int v)
{
    e[++num].ver=v;
    e[num].nxt=head[u];
    head[u]=num;
}
void dfs(int x)
{
    vis[x]=1;
    for(register int i=head[x];i;i=e[i].nxt)
    {
        int y=e[i].ver;
        if(vis[y])
            continue;
        vis[y]=1;
        fa[y]=x;
        dfs(y);
    }
}
void dp(int x)
{
    f[x][0]=0;
    f[x][1]=1;
    for(register int i=head[x];i;i=e[i].nxt)
    {
        int y=e[i].ver;
        if(y==fa[x])
            continue;
        dp(y);
        f[x][0]+=f[y][1];
        f[x][1]+=min(f[y][0],f[y][1]);
    }
}
int main()
{
    n=read();
    num=0;
    for(register int i=1;i<=n;i++)
    {
        x=read()+1;
        cnt=read();
        for(register int j=1;j<=cnt;j++)
        {
            y=read()+1;
            adde(x,y);
            adde(y,x);
        }
    }
    dfs(1);
    dp(1);
    printf("%d\n",min(f[1][0],f[1][1]));
    return 0;
}

标签:游戏,limits,int,Luogu,P2016,为根,根树,节点
来源: https://www.cnblogs.com/Peter0701/p/11837813.html