题目

解法跟 dalao @real_ljs 类似,但没有用到递归


【分析】

题目相当于需要求覆盖这颗树需要的最小点数

用 \(Dp_{i,0/1}\) 表示在这棵树中,以 \(i\) 为根节点的子树选/不选根节点的情况下,覆盖这棵树所有边需要的最小点数

所以,当不选这个节点 \(i\) 时,则所有 以其子节点为根节点的子树 都必选根节点

当选择这个节点 \(i\) 时,它能连接到所有的子节点,所以 以其子节点为根节点的子树 可以选则其根节点,也可以不选

归纳成方程组,可能更容易理解:

\(\begin{cases}Son_i\neq \varnothing\\\ \\ \displaystyle Dp_{i,0}=\sum_{j\in Son_i}Dp_{j,1}\\\ \\\displaystyle Dp_{i,1}=1+\sum_{j\in Son_i}min(Dp_{j,0},Dp_{j,1})\end{cases}\)

其中,\(Son_i\) 为 \(i\) 的子节点集合

显然,边界为

\(\begin{cases}Son_i=\varnothing\\Dp_{i,0}=0\\Dp_{i,1}=1\end{cases}\)

如果定义 \(Son_i=\varnothing\) 时 \(\displaystyle \sum_{j\in Son_i}Dp_{j,1}=\sum_{j\in Son_i}min(Dp_{j,0},Dp_{j,1})=0\)

递推式及其边界便能写在一起了:

\(\begin{cases}\displaystyle Dp_{i,0}=0+\sum_{j\in Son_i}Dp_{j,1}\\\ \\\displaystyle Dp_{i,1}=1+\sum_{j\in Son_i}min(Dp_{j,0},Dp_{j,1})\end{cases}\)

答案即为 \(min(Dp_{root,0},Dp_{root,1})\)


很显然,根据树形dp的特点,我们要从叶子开始回溯回去,一般用dfs,或者说是递归,来辅助进行

但是,毕竟本人不喜欢递归,所以想到了一个方法可以避免使用递归

我们来想想,这题的树形dp只要满足子节点的dp在父节点之前完成即可

那我们可以先从根节点开始bfs一下,把树压成一条链,然后再把bfs访问的节点倒序完成dp即可

因为bfs过程中,子节点一定由父节点拓展而来,故子节点在bfs中一定在父节点之后访问到

dp的时候我们倒叙访问,就一定能保证子节点先完成dp,再由父节点完成dp

具体实现方法也不难,最后倒叙访问实际上就是一个栈,我们让这个数组在bfs的时候做队列,dp的时候再当作栈即可


考虑一下时间复杂度:

读入各个节点需要 \(O(n)\),读入他们的子节点数也需要 \(O(n)\)

读入子节点为 \(\displaystyle \sum_{i=1}^n Card(Son_i)=n-1\) ,也为 \(O(n)\) 的

找根节点、bfs为 \(O(n)\)

dp的内层次为 \(O(\ \ Card(Son_i)\ \ )\)

dp的复杂度为 \(\displaystyle O(\ \ \sum_{i=1}^n[1+Card(Son_i)]\ \ )=O(\ \ \displaystyle n+\sum_{i=1}^nCard(Son_i)\ \ )=O(n+n-1)\)

因此,dp的复杂度为 \(O(n)\)

很显然,总复杂度也为 \(O(n)\)

简直快得飞起


【代码】

那本蒟蒻就放 我码风极丑的 代码了

#include<cstdio>
#include<cstring>
using namespace std;
#define f(a,b,c,d) for(register int a=b,c=d;a<=c;a++)
#define g(a,b,c,d) for(register int a=b,c=d;a>=c;a--)
const int MAXN=1510;
typedef int i32;
typedef unsigned int u32;
typedef long long int i64;
typedef unsigned long long int u64;
typedef i32 ar[MAXN];
typedef i32 mt[MAXN][MAXN];
#define cls(s) memset(s,0,sizeof(s))
inline i32 min(int a,int b) { return (a<b)?a:b; }
//条件反射般的一堆定义 namespace IO{
// #define LOCAL
#ifdef LOCAL
inline char gc() { return getchar(); }
#else
inline char gc(){
static char s[1<<20|1]={0},*p1=s,*p2=s;
return (p1==p2)&&(p2=(p1=s)+fread(s,1,1<<20,stdin),p1==p2)?EOF:*(p1++);
}
#endif
inline i32 read(){
register int ans=0;register char c=gc();register bool neg=0;
while(c<48||c>57) neg^=!(c^'-'),c=gc();
while(c>=48&&c<=57) ans=(ans<<3)+(ans<<1)+(c^48),c=gc();
return neg?-ans:ans;
}
char Output_Ans[1<<20|1]={0},*Output_Cur=Output_Ans;
inline void output() { Output_Cur-=fwrite(Output_Ans,1,Output_Cur-Output_Ans,stdout); }
inline void print(char c){
if(Output_Cur-Output_Ans+1>>20) output();
*(Output_Cur++)=c;
}
inline void print(i32 ans){
char s[20]={0};
if(Output_Cur-Output_Ans+sprintf(s,"%d",ans)>>20) output();
Output_Cur+=sprintf(Output_Cur,"%d",ans);
}
}
using namespace IO;
//条件反射般的读入输出优化 i32 d_N,d_Cur;
ar ar_d_Stk;
mt mt_d_Son;
inline void pre(){
d_N=read();
bool b_Notroot[MAXN]={0};
f(i,1,I,d_N){
i32 d_Pos=read();
mt_d_Son[d_Pos][0]=read();
//第一位存子节点数
f(j,1,J,mt_d_Son[d_Pos][0])
mt_d_Son[d_Pos][j]=read(),b_Notroot[ mt_d_Son[d_Pos][j] ]=1;
}
//读入,并同时判定根节点 ar_d_Stk[d_Cur]=0;
while(b_Notroot[ ar_d_Stk[d_Cur] ]) ar_d_Stk[d_Cur]++;
d_Cur++;
//寻找根节点,放入队列头 i32 d_Head=0;
while(d_Head<d_Cur){
i32 d_Pos=ar_d_Stk[d_Head++];
f(i,1,I,mt_d_Son[d_Pos][0])
ar_d_Stk[d_Cur++]=mt_d_Son[d_Pos][i];
}
//bfs压树为链
}
int main(){
pre();
i32 mt_d_Dp[MAXN][2]={0};
while(d_Cur--){
i32 i=ar_d_Stk[d_Cur];//取出栈顶
mt_d_Dp[i][0]=0,mt_d_Dp[i][1]=1;
if(mt_d_Son[i][0])
f(j,1,J,mt_d_Son[i][0]){
i32 d_Kid=mt_d_Son[i][j];
mt_d_Dp[i][0]+=mt_d_Dp[d_Kid][1];
mt_d_Dp[i][1]+=min(mt_d_Dp[d_Kid][0],mt_d_Dp[d_Kid][1]);
}
}
print( min(mt_d_Dp[ ar_d_Stk[d_Cur] ][0],mt_d_Dp[ ar_d_Stk[d_Cur] ][1]) );
output();
return 0;
}

最后安利一下 本蒟蒻的博客

题解 P2016 【战略游戏】的更多相关文章

  1. 洛谷P2016 战略游戏

    P2016 战略游戏 题目描述 Bob喜欢玩电脑游戏,特别是战略游戏.但是他经常无法找到快速玩过游戏的办法.现在他有个问题. 他要建立一个古城堡,城堡中的路形成一棵树.他要在这棵树的结点上放置最少数目 ...

  2. P2016 战略游戏——树形DP大水题

    P2016 战略游戏 树形DP 入门题吧(现在怎么是蓝色标签搞不懂): 注意是看见每一条边而不是每一个点(因为这里错了好几次): #include<cstdio> #include< ...

  3. 【题解】Luogu p2016 战略游戏 (最小点覆盖)

    题目描述 Bob喜欢玩电脑游戏,特别是战略游戏.但是他经常无法找到快速玩过游戏的办法.现在他有个问题. 他要建立一个古城堡,城堡中的路形成一棵树.他要在这棵树的结点上放置最少数目的士兵,使得这些士兵能 ...

  4. 洛谷P2016战略游戏

    传送门啦 战略游戏这个题和保安站岗很像,这个题更简单,这个题求的是士兵人数,而保安站岗需要求最优价值. 定义状态$ f[u][0/1] $ 表示 $ u $ 这个节点不放/放士兵 根据题意,如果当前节 ...

  5. [洛谷P2016] 战略游戏 (树形dp)

    战略游戏 题目描述 Bob喜欢玩电脑游戏,特别是战略游戏.但是他经常无法找到快速玩过游戏的办法.现在他有个问题. 他要建立一个古城堡,城堡中的路形成一棵树.他要在这棵树的结点上放置最少数目的士兵,使得 ...

  6. P2016 战略游戏 (树形DP)

    题目描述 Bob喜欢玩电脑游戏,特别是战略游戏.但是他经常无法找到快速玩过游戏的办法.现在他有个问题. 他要建立一个古城堡,城堡中的路形成一棵树.他要在这棵树的结点上放置最少数目的士兵,使得这些士兵能 ...

  7. 【洛谷P2016战略游戏】

    树形dp的经典例题 题目描述 Bob喜欢玩电脑游戏,特别是战略游戏.但是他经常无法找到快速玩过游戏的办法.现在他有个问题. 他要建立一个古城堡,城堡中的路形成一棵树.他要在这棵树的结点上放置最少数目的 ...

  8. Luogu P2016 战略游戏(树形DP)

    题解 设\(f[u][0/1/2]\)表示当前节点\(u\),放或不放(\(0/1\))时其子树满足题目要求的最小代价,\(2\)表示\(0/1\)中的最小值. 则有: \[ f[u][0]=\sum ...

  9. 洛谷 P2016 战略游戏

    题意简述简述 求一棵树的最小点覆盖 题解思路 树形DP dp[i][0]表示第i个点覆盖以i为根的子树的最小值,且第i个点不放士兵 dp[i][1]表示第i个点覆盖以i为根的子树的最小值,且第i个点放 ...

  10. P2016 战略游戏

    传送门 思路: 前置知识——普通树D: ▲普通的树形 DP : 设 f [ i ][ 0 ] 表示这个点不取,则它的所有子节点都要取:f [ i ][ 1 ] 表示这个点取,则它的子节点取与不取对之前 ...

随机推荐

  1. [JZOI]1251.收费站[二分][最短路]

    Description 在某个遥远的国家里,有n个城市.编号为1,2,3,--,n. 这个国家的政府修建了m条双向的公路.每条公路连接着两个城市.沿着某条公路,开车从一个城市到另一个城市,需要花费一定 ...

  2. 001、在本地搭建SAP虚拟机环境,用于各种暴力操作

    一.在某网盘下载一个SAP虚拟机,用于SAP学习和相关的测试.打开图中的服务器,点击运行,等灯都变成绿色 二.点击打开熟悉的SAP登录图标 三.很完美的运行起来了. 友情提示:SAP对电脑配置要求挺高 ...

  3. Hadoop组件详解(随缘摸虾)

    1.1. Hadoop组成: Hadoop = hdfs(存储) + mapreduce(计算) + yarn(资源协调) + common(工具包) + ozone(对象存储) + submarin ...

  4. Bean XML 配置(2)- Bean作用域与生命周期回调方法配置

    系列教程 Spring 框架介绍 Spring 框架模块 Spring开发环境搭建(Eclipse) 创建一个简单的Spring应用 Spring 控制反转容器(Inversion of Contro ...

  5. java 实体 set数据 报空指针异常

    今天在做一个调用阿里云AXB隐私保护,需要调用通话记录的消费队列,然后set到实体中,然后插入到数据库,但是set的这一步报错 以为工具拿不到值,然后打印发现是有值的, 然后再看一下实例的类型是没错的 ...

  6. C# NPOI的数据批量导入数据库

    public ActionResult Upload(HttpPostedFileBase Namefile)        {            //判断文件是否存在            if ...

  7. 基础语法-其它流程控制语句break和continue

    基础语法-其它流程控制语句break和continue 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.break语句 /** * break语句 * @author 尹正杰 * ...

  8. 19 ~ express ~ 文章的增加 , 查看 ,修改 ,删除

    一,前台 1,添加文章 /views/admin/content_add.html {% extends 'layout.html' %} {% block main %} <ol class= ...

  9. BZOJ 3442 学习小组

    题解: 神建图 普通的二分图费用流建完后 添加学生x->t 容量为k-1的边 表示尽量让x参加一个活动,剩下的k-1次机会可以不参加 #include<iostream> #incl ...

  10. jQuery元素的左右移动

    1.下载jQuery,并导入:https://blog.csdn.net/weixin_44718300/article/details/88746796 2.代码实现: <!DOCTYPE h ...