当前位置: 首页 > news >正文

P1041 [NOIP 2003 提高组] 传染病控制

题目含义

有一棵树,当前根节点已经被传染,传染将顺着边每次前进一层(即传染至下一层的节点中),可以每次在当前层切断一条边,以保住切断后的子树部分,求如何切能够使得传染的人最少,即最后留在树上的节点数最少。

跑一下样例看看我的理解对不对

在这里插入图片描述
最后剩下3个点。

看起来理解没啥问题

分析过程

那如何做呢?即如何选择每次删哪条边?

我们发现n=300,搜索是ok的,接下来直接搜索,每一种切割方案都被搜索到,在这个过程中迭代出最优的方案就行。
能不能剪枝呢?
在这一过程中,选择最优化剪枝,即留下的结点数已经被ans大了,就不需要再继续算了,它肯定不会是答案了。

规划一下如何写?

从根结点开始搜,搜到第i层,在这一层中枚举没有被删除的边,构建答案。
(这里提示我们要记录层,记录哪些边被删了,哪些边没被删)

搜索到最后一层,更新答案,即此时留下几个点,可以用n-删除的点的数量
(要预处理出每个点的层号,以每个结点为根的子树的大小,此外,每一层上有哪些边是也需要处理的。)

void dfs(int u, int s)
{ans = min(ans, s);//枚举每一层的边 for (int i = 0; i < level[u].size(); i ++ ){int j = level[u][i];//找到一条没有被删的边 if (!c[j]){dfs_draw(j, 1);//删它和它子树的边// 向下一层搜索,还有结点s-size[e[j]]个 dfs(u + 1, s - cnt[e[j]]);dfs_draw(j, 0);//恢复现场 }}
}

要删除的边,同时通往它下面所有的子结点的边都会被删掉,可以对这这边打个标记。

/x/删了该边标为1,没删为0 
void cut(int j, int color)
{c[j] = color;//给这条边标记颜色//这条边指向结点的链表 for (int i = h[e[j]]; ~i; i = ne[i])if (i != (j ^ 1))   // i不是j的反向边cut(i, color);
}

综上,在实现时,先通过dfs预处理出每个点的深度,它的父亲,以它为根的子树的节点个数。

//删了该边标为1,没删为0 
void cut(int j, int color)
{c[j] = color;//这条边指向结点的链表 for (int i = h[e[j]]; ~i; i = ne[i])if (i != (j ^ 1))   // i不是j的反向边cut(i, color);
}

代码实现

#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>using namespace std;const int N = 310, M = N * 2;int n, m;
int h[N], e[M], ne[M], idx;
vector<int> level[N];
int c[M], siz[N];
int ans = N;void add(int a, int b)
{e[idx] = b, ne[idx] = h[a], h[a] = idx ++ ;
}int dfs1(int u, int depth, int father)
{siz[u] = 1;for (int i = h[u]; ~i; i = ne[i]){int j = e[i];if (j == father) continue;siz[u] += dfs1(j, depth + 1, u);//i号边是第 depth 层的边(边的索引)level[depth].push_back(i);}return siz[u];
}
//删了该边标为1,没删为0 
void cut(int j, int color)
{c[j] = color;//这条边指向结点的链表 for (int i = h[e[j]]; ~i; i = ne[i])if (i != (j ^ 1))   // i不是j的反向边cut(i, color);
}void dfs(int u, int s)
{ans = min(ans, s);//枚举每一层的边 for (int i = 0; i < level[u].size(); i ++ ){int j = level[u][i];//找到一条没有被删的边 if (!c[j]){cut(j, 1);//删它和它子树的边// 向下一层搜索,还有结点s-size[e[j]]个 dfs(u + 1, s - siz[e[j]]);cut(j, 0);//恢复现场 }}
}int main()
{cin >> n >> m;memset(h, -1, sizeof h);for (int i = 0; i < m; i ++ ){int a, b;cin >> a >> b;add(a, b), add(b, a);}dfs1(1, 0, -1);//从0层开始搜,现在还有n个 dfs(0, n);cout << ans << endl;return 0;
}

我想说的是……

  1. 涉及到层、点、边的问题,代码实现有点绕,要注意
http://www.dtcms.com/a/525509.html

相关文章:

  • 武进建设局网站和业务多一样的平台
  • eclipse可以做门户网站嘛公司建设网站的 计划书
  • Linux小课堂: 从IPv4到IPv6、主机名解析及网络接口管理
  • ant design vue使用date组件,判断要清空却失效的问题
  • 百度seo搜索百度推广优化技巧
  • 手机版网站建设方案福建建设工程信息网官网查询
  • 终结工艺数据分散管理:金仓数据库平替MongoDB,实现参数、配方、流程一体贯通
  • SAP 长文本弹窗函数 及控件使用
  • 常规同轴光源在工业视觉检测上的应用
  • 建设国家游戏网站免费创建音乐网站
  • 网站源码怎么做网站热点新闻事件及观点简单版
  • windows服务器mstsc远程桌面连接输入用户名后连接时自带拼接了本机计算机名称导致用户名一直错误,无法远程,使用.\用户名格式解决
  • 【Diffusion Model】奠基之作DDPM详解
  • 4a级景区网站建设方寸网站建设
  • 【图像超分】论文复现:轻量化超分 | SPAN的Pytorch源码复现,跑通源码进行训练、测试
  • 小红书小组件开发 最早踩坑版
  • 厚街外贸网站建设公司wordpress.org hosting
  • 现在网站用什么语言做最好WordPress整站下载器
  • 用最少数量的箭引爆气球--leetcode
  • Linux中网络初始化函数sock_init的实现
  • 数据结构——KMP算法
  • 湖北微网站建设报价我的手机网站
  • Spring集成WebSocket
  • MinerU系列最新迭代版本上线,专为高精度、高效率的文档解析任务设计;清华、字节联合推出HuMo,实现三模态协同生成人物视频
  • 什么是企业营销型网站seo公司优化排名
  • 洛阳有做网站开发的吗wordpress重构
  • 呼和浩特网站建设电话西安网页设计培训
  • uniapp开发小程序,实现开通会员卡页面
  • 微信小程序开发案例 | 简易登录小程序
  • uniapp开发小程序,Canvas实现海报生成邀请码,邀请好友功能