【思路】

题目给出一棵树。第\(i\)步拆的一定是第\(i\)层与第\(i+1\)层之间的连边,否则不是最优(自行证明即可),所以可以暴力枚举每一次拆哪一个节点与上一个节点的连边。

把所有节点所在的层数存下来,一号点在第\(1\)层,枚举每一层的每个节点(由于\(1\)号节点已经被感染,从第二层开始搜索就可以了)

大概可分为以下几步:

  • 存好一整棵树

  • 把每一层的节点都存在一个数组里面

  • 标记以ii号节点为根节点的子树的节点个数

  • 标记与回溯

  • 暴力搜索

【细节精讲】

1、树的存储

关于多叉树的存储,这里介绍一种简单有效的方法。考虑如下代码:

struct Node
{
int father;
int child[MAXN];
}tree[MAXN];

\(tree[i]\)存\(i\)号节点的所有信息:

\(father\)存父亲(在这题没有用) ; \(child[]\)存它所有的孩子 ; \(child[0]\)是它孩子的个数。

由于数据范围很小,我们不用担心造成空间过多的浪费。

结构体构建完成之后,我们就可以在读入的同时把整棵树存好。

n=read();p=read();
for(int i=1;i<=p;i++)
{
int x=read(),y=read();
if(x>y)swap(x,y);
tree[y].father=x;
tree[x].child[++tree[x].child[0]]=y;
}

2 、标记深度

如果能够理解,标记深度是比较简单的。

如图:我们令\(1\)号节点的深度为\(1\) ; 则\(2,3\)节点深度为\(2\) ; \(4,5,6,7\)节点的深度为\(3\); \(8\)节点的深度为\(4\)。这棵树一共有\(4\)层。

代码用\(deep[i][j]\)存第\(i\)层第\(j\)个节点的编号。\(deep[i][0]\)是第\(i\)层一共的节点数。

inline void getdeep(int now,int Nowdeep)//当前的节点标号是now,层数是Nowdeep
{
maxdeep=max(maxdeep,Nowdeep);//标记一共有几层
for(int i=1;i<=tree[now].child[0];i++)
{
deep[Nowdeep][++deep[Nowdeep][0]]=tree[now].child[i];//把这个节点放到第i层的数组中
getdeep(tree[now].child[i],Nowdeep+1);//以这个点为父节点继续标记它的儿子。每个节点的深度等于它父节点的深度+1
}
}

3、切断问题

我们知道,只要一个点与上层点的传播途径被切断,即这个点不会得传染病,那么以这个点为根节点的整个子树都应该被标记为安全。

这一段代码用来标记\(now\)这个节点为根节点的子树一共有多少节点,存在\(num[]\)中。

inline int getnum(int now)
{
for(int i=1;i<=tree[now].child[0];i++)
num[now]+=getnum(tree[now].child[i]);
return num[now];
}

4、回溯

接下来,我们切断了这个节点,相应地,以这个点为根节点的子树都应该被标记。(\(tag=1\)表示标记,\(tag=0\)表示删去标记,用于回溯)

inline void work(int now,bool tag)
{
vis[now]=tag;
for(int i=1;i<=tree[now].child[0];i++)
{
vis[tree[now].child[i]]=tag;
work(tree[now].child[i],tag);
}
}

5、搜索

做完上面这些铺垫操作之后,我们可以开始整个代码的核心:搜索了。

首先可以想到如下代码

inline void DFS(int now,int cnt)
{
if((now==maxdeep))
{
ans=min(ans,cnt);
return;
}
for(int i=1;i<=deep[now][0];i++)
{
if(vis[deep[now][i]])
continue;
work(deep[now][i],1);
DFS(now+1,cnt-num[deep[now][i]]);
work(deep[now][i],0);
}
}

但是提交这段代码的话只能得80分。为什么呢?

我们可以考虑这样一棵树:

它是一条链。我们第一次只能切断1号节点和2号节点之间的连边,这样第三层所有的节点就都被标记了。那么问题是什么呢?根本就搜不到最后一层的节点,导致答案根本没有更新!

于是我们优化一下搜索代码:

inline void DFS(int now,int cnt)
{
int tot=0;//记录总数
if((now==maxdeep))
{
ans=min(ans,cnt);
return;
}
for(int i=1;i<=deep[now][0];i++)
{
if(vis[deep[now][i]])
{
tot++;
continue;
}
work(deep[now][i],1);
DFS(now+1,cnt-num[deep[now][i]]);
work(deep[now][i],0);
}
if(tot==deep[now][0])//如果全部都被访问过了,那么直接更新答案
ans=min(ans,cnt);
}

【代码】

#include<bits/stdc++.h>
using namespace std;
const int MAXN=300+10;
int n,p;
struct Node
{
int father;
int child[MAXN];
}tree[MAXN];
int num[MAXN];
int deep[MAXN][MAXN];
int maxdeep=0;
bool vis[MAXN];
int ans=0x3f3f3f3f;
inline int read()
{
int tot=0;
char c=getchar();
while(c<'0'||c>'9')
c=getchar();
while(c>='0'&&c<='9')
{
tot=(tot<<1)+(tot<<3)+c-'0';
c=getchar();
}
return tot;
}
inline void getdeep(int now,int Nowdeep)
{
maxdeep=max(maxdeep,Nowdeep);
for(int i=1;i<=tree[now].child[0];i++)
{
deep[Nowdeep][++deep[Nowdeep][0]]=tree[now].child[i];
getdeep(tree[now].child[i],Nowdeep+1);
}
}
inline int getnum(int now)
{
for(int i=1;i<=tree[now].child[0];i++)
num[now]+=getnum(tree[now].child[i]);
return num[now];
}
inline void work(int now,bool tag)
{
vis[now]=tag;
for(int i=1;i<=tree[now].child[0];i++)
{
vis[tree[now].child[i]]=tag;
work(tree[now].child[i],tag);
}
}
inline void DFS(int now,int cnt)
{
int tot=0;
if((now==maxdeep))
{
ans=min(ans,cnt);
return;
}
for(int i=1;i<=deep[now][0];i++)
{
if(vis[deep[now][i]])
{
tot++;
continue;
}
work(deep[now][i],1);
DFS(now+1,cnt-num[deep[now][i]]);
work(deep[now][i],0);
}
if(tot==deep[now][0])
ans=min(ans,cnt);
}
int main()
{
n=read();p=read();
fill(num+1,num+1+n,1);
for(int i=1;i<=p;i++)
{
int x=read(),y=read();
if(x>y)swap(x,y);
tree[y].father=x;
tree[x].child[++tree[x].child[0]]=y;
}
/*for(int i=1;i<=n;i++)
{
for(int j=1;j<=tree[i].child[0];i++)cout<<tree[i].child[j]<<" ";
cout<<endl;
}*/
getdeep(1,2);
/*for(int i=2;i<=maxdeep;i++)
{
for(int j=1;j<=deep[i][0];j++)cout<<deep[i][j]<<" ";
cout<<endl;
}*/
getnum(1);
DFS(2,n);
printf("%d\n",ans);
return 0;
}

\[\color{red}\large\text{完结撒花}
\]

参考博客

洛谷 题解 P1041 【传染病控制】的更多相关文章

  1. 洛谷 题解 UVA572 【油田 Oil Deposits】

    这是我在洛谷上的第一篇题解!!!!!!!! 这个其实很简单的 我是一只卡在了结束条件这里所以一直听取WA声一片,详细解释代码里见 #include<iostream> #include&l ...

  2. 洛谷 题解 P1600 【天天爱跑步】 (NOIP2016)

    必须得说,这是一道难题(尤其对于我这样普及组205分的蒟蒻) 提交结果(NOIP2016 天天爱跑步): OJ名 编号 题目 状态 分数 总时间 内存 代码 / 答案文件 提交者 提交时间 Libre ...

  3. 洛谷题解P4314CPU监控--线段树

    题目链接 https://www.luogu.org/problemnew/show/P4314 https://www.lydsy.com/JudgeOnline/problem.php?id=30 ...

  4. 洛谷题解 CF777A 【Shell Game】

    同步题解 题目翻译(可能有童鞋没读懂题面上的翻译) 给你三张牌0,1,2. 最初选一张,然后依次进行n次交换,交换规则为:中间一张和左边的一张,中间一张和右边一张,中间一张和左边一张...... 最后 ...

  5. 洛谷题解 CF807A 【Is it rated?】

    同步题解 题目 好吧,来说说思路: 1.先读入啦~(≧▽≦)/~啦啦啦 2.判断a[i]赛前赛后是否同分数,如果分数不同,则输出,return 0 . 3.如果同分数,则判断a[i]赛前(或赛后)是否 ...

  6. 洛谷题解 P1138 【第k小整数】

    蒟蒻发题解了 说明:此题我用的方法为桶排(我翻了翻有人用了桶排只不过很难看出来,可能有些重复的,这个题只是作为一个专门的桶排来讲解吧) (不会算抄袭吧 ‘QWaWQ’) 简单来说(会的人跳过就行): ...

  7. 【洛谷题解】P2303 [SDOi2012]Longge的问题

    题目传送门:链接. 能自己推出正确的式子的感觉真的很好! 题意简述: 求\(\sum_{i=1}^{n}gcd(i,n)\).\(n\leq 2^{32}\). 题解: 我们开始化简式子: \(\su ...

  8. 洛谷题解 P2865 【[USACO06NOV]路障Roadblocks】

    链接:https://www.luogu.org/problemnew/show/P2865 题目描述 Bessie has moved to a small farm and sometimes e ...

  9. 洛谷题解:P1209 【[USACO1.3]修理牛棚 Barn Repair】

    原题传送门:https://www.luogu.org/problemnew/show/P1209 首先,这是一道贪心题.  我们先来分析它的贪心策略.  例如,样例:  4 50 18  3 4 6 ...

随机推荐

  1. 对象+String

    public class Fruit { public String toString() { return "Fruit toString."; } public static ...

  2. MyBatis项目配置案例详解与Web下的增删改查实现[附项目源码]

    MyBatis项目案例 项目图示: 项目源码地址:https://github.com/JluTiger/mybatispro 1.项目功能 项目案例:后台管理系统用户数据维护平台 所有用户数据查询 ...

  3. SpringMVC从Session域中获取值

    SpringMVC从Session域中获取值 SpringMVC环境自行搭建 第一步:前端页面 第二步.后台代码 第三步.响应视图 第四步.在当前处理器所在的类设置@SessionAttributes ...

  4. listbox demo

    功能 添加.删除.修改选中的项.上移.下移.清空.保存列表.加载列表.判断内容是否重复.查找.模糊查找.取消选择.上一条.下一条.第一条.最后一条 下载地址:https://download.csdn ...

  5. Mysql 查看所有线程,被锁的表等

    ## 查看所有MYSQl相关的线程 > show full processlist; ## 杀死线程id为2的线程 > kill 2 ## 查看服务器状态 > show status ...

  6. Perl关于分椰子的趣味问题

    话说某天一艘海盗船被天下砸下来的一头牛给击中了,5个倒霉的家伙只好逃难到一个孤岛,发现岛上孤零零的,幸好有有棵椰子树,还有一只猴子! 大家把椰子全部采摘下来放在一起,但是天已经很晚了,所以就睡觉先晚上 ...

  7. 动化安装SQL Server+SP就那么简单

    随着业务.企业规模的日益壮大,DB的数量也在不断增多,配置一台新增DB,从服务器的参数配置,磁盘阵列规划,DB安装部署,DB参数调优等等一列步骤下来,手工操作的效率变得越来越低,因为我负责的数据库近些 ...

  8. SKU是什么意思?

    在做电商项目时候必定会遇到这个词,那是什么意思呢?其实简单来讲就是一个单位. SKU全称为Stock Keeping Unit(库存量单位),即库存进出计量的基本单元,可以是以件,盒,托盘等为单位.S ...

  9. Ubuntu16.04下升级Python到3.6.5

    本文链接:https://blog.csdn.net/chaiyu2002/article/details/82698376原帖存于IT老兵博客.Ubuntu16.04下升级Python到3.6.5 ...

  10. IDEA一些自动补全方式

    第一种:系统自带:可以CTRL + j 可以查看 psvm 也就是public static void main的首字母. 依次还有在方法体内键入for会有一个fori的提示,选中然后tab键,就会自 ...