P1041 [NOIP2003 提高组] 传染病控制

news/2024/4/20 3:42:50/文章来源:https://blog.csdn.net/dacongming123355/article/details/130371944

题目背景

本题是错题,后来被证明没有靠谱的多项式复杂度的做法。测试数据非常的水,各种玄学做法都可以通过,不代表算法正确。因此本题题目和数据仅供参考。


近来,一种新的传染病肆虐全球。蓬莱国也发现了零星感染者,为防止该病在蓬莱国大范围流行,该国政府决定不惜一切代价控制传染病的蔓延。不幸的是,由于人们尚未完全认识这种传染病,难以准确判别病毒携带者,更没有研制出疫苗以保护易感人群。于是,蓬莱国的疾病控制中心决定采取切断传播途径的方法控制疾病传播。经过 WHO(世界卫生组织)以及全球各国科研部门的努力,这种新兴传染病的传播途径和控制方法已经研究清楚,剩下的任务就是由你协助蓬莱国疾控中心制定一个有效的控制办法。

题目描述

研究表明,这种传染病的传播具有两种很特殊的性质;

第一是它的传播途径是树型的,一个人 �X 只可能被某个特定的人 �Y 感染,只要 �Y 不得病,或者是 ��XY 之间的传播途径被切断,则 �X 就不会得病。

第二是,这种疾病的传播有周期性,在一个疾病传播周期之内,传染病将只会感染一代患者,而不会再传播给下一代。

这些性质大大减轻了蓬莱国疾病防控的压力,并且他们已经得到了国内部分易感人群的潜在传播途径图(一棵树)。但是,麻烦还没有结束。由于蓬莱国疾控中心人手不够,同时也缺乏强大的技术,以致他们在一个疾病传播周期内,只能设法切断一条传播途径,而没有被控制的传播途径就会引起更多的易感人群被感染(也就是与当前已经被感染的人有传播途径相连,且连接途径没有被切断的人群)。当不可能有健康人被感染时,疾病就中止传播。所以,蓬莱国疾控中心要制定出一个切断传播途径的顺序,以使尽量少的人被感染。

你的程序要针对给定的树,找出合适的切断顺序。

输入格式

输入格式:
第一行是两个整数 �n 和 �p。
接下来 �p 行,每一行有 22 个整数 �i 和 �j,表示节点 �i 和 �j 间有边相连。(意即,第 �i 人和第 �j 人之间有传播途径相连)。其中节点 11 是已经被感染的患者。

输出格式

11 行,总共被感染的人数。

输入输出样例

输入 #1复制

7 6
1 2
1 3
2 4
2 5
3 6
3 7

输出 #1复制

3

说明/提示

对于 100%100% 的数据,1≤�≤3001≤n≤300。

【题目来源】

NOIP 2003 提高组第四题

如果你初学搜索,如何一步一步无伤A掉搜索真题?

让我们以初学者的角度走进改题;

警告:本篇题解面向初学者非最优解或非常规解法,神犇请绕道

做一道题首先需要的是逐步分析:

  1. 题目给定了一棵树, 树的节点 n <= 300 ,同理的变数p = n - 1; 或许是搜索?

  2. 从节点1开始传染,所谓切断一条路径, 不难转换为标记其中一颗子树

  3. 每个传染阶段为每一个已被标记“得病”的节点向下传染,传染次数在最坏情况下刚好为叶节点到1节点的距离; 或许是拓扑?

要寻找正确的解题方法总要进行不断的思考

首先先思考拓扑相关, 从末节点倒推是否是一种可行的方法?

事实证明这种方法在题目限制下是几乎不可行的;

(事实证明可以用来进行一定量的预处理)

那么对我来说就只有搜索一条路可以走;

然后是要求输出当传染人数最少的情况下的人数;

同理为未被传染人数最多时传染人数;

那么首先我们要建立相关的代码框架

1.先从输入开始:

值得一提的是输入的边并没有说明是父节点指向子节点或子节点指向父节点

应该想方法处理

2.dfs函数

不难得到,一个节点若要被传染,那么传染到该节点的第x个传染阶段一定是该节点到1节点的距离

接下来是我个人的想法:

显然以节点下标作为dfs传入参数来进行相关处理不太可行;

那么不如我们以距离1节点的距离x为传入参数

然后对所有距离1节点距离为x的节点进行处理

即为选择一颗子树进行切除, 然后进行下一层dfs

切除该子树要进行的操作为标记所有该子树上的节点并统计节点数量

同时要保证该子树的父节点为在前几层的递归中未被切除;

当无子树可以切除时dfs函数变走到尽头

然后进行思考一下回溯, 这个是较简单的,同理与标记

int clean(int i){bol[i] = true;int num = 1;int p = f[i].size();for (int j = 0; j < p; ++j){num += clean(f[i][j]);}return num;
}
void reclean(int i){bol[i] = false;int p = f[i].size();for (int j = 0; j < p; ++j){reclean(f[i][j]);}
}

每次进行一次切除就要便利一遍全部子节点显然缺乏效率;

但对于本题的数据范围来说还是可以接受的;

上文代码中用到了一个vector, 里面存的是该节点的子节点

那么回到题目头, 我们该如何处理保证f数组里面都为该节点的子节点呢?

用另外一个数组存入输入的所有边

简单套用一个最短路模板统计距离

然后将所有合法的边push入f即可;

为了要保证可以正常处理距离节点1距离为x的全部节点

也要进行简单的统计

void resolve(int i, int cen){b[cen][cnt[cen]] = i;++cnt[cen];int p = k[i].size();for (int j = 0; j < p; ++j){if (dis[k[i][j]] == dis[i]+1){resolve(k[i][j], cen+1);f[i].push_back(k[i][j]);}}
}

最后统计得未被传染人数最多时的人数

输出节点总数减未被传染人数获得正解;

具体细节详见代码

本人AC代码:(327ms)

#include<cstdio>
#include<iostream>
#include<cstring>
#include<vector>
#include<queue>
#define LL long long
using namespace std;
int n, p, t1, t2, b[305][305], cnt[305], maxx, dis[305];
bool bol[305], vis[305];
vector <int> k[305], f[305];
struct node{int x, quan;node (int a, int b) : x(a), quan(b){}friend bool operator < (node a, node b){return a.quan > b.quan;}
};
int clean(int i){bol[i] = true;int num = 1;int p = f[i].size();for (int j = 0; j < p; ++j){num += clean(f[i][j]);}return num;
} //标记部分
void reclean(int i){bol[i] = false;int p = f[i].size();for (int j = 0; j < p; ++j){reclean(f[i][j]);}
} //回溯部分
void dfs(int cen, int tot){maxx = max(maxx, tot);for (int i = 0; i < cnt[cen]; ++i){if (!bol[b[cen][i]]){int num = clean(b[cen][i]);tot += num;dfs(cen+1, tot);reclean(b[cen][i]);tot -= num;}}
} //dfs核心函数
void resolve(int i, int cen){b[cen][cnt[cen]] = i;++cnt[cen];int p = k[i].size();for (int j = 0; j < p; ++j){if (dis[k[i][j]] == dis[i]+1){resolve(k[i][j], cen+1);f[i].push_back(k[i][j]);}}
} //预处理第二部分
void solve(){priority_queue <node> que;for (int i = 0; i <= n; ++i) dis[i] = 999;dis[1] = 0;que.push(node(1, 0));while (!que.empty()){node temp = que.top();que.pop();int x = temp.x;int p = k[x].size();for (int j = 0; j < p; ++j){if (dis[k[x][j]] > dis[x]+1){dis[k[x][j]] = dis[x]+1;que.push(node(k[x][j], dis[k[x][j]]));}}}resolve(1, 0);
} //最短路算法进行预处理
//实际上以节点0开始进行拓扑排序效率更高
int main(){scanf("%d %d", &n, &p);for (int i = 0; i < p; ++i){scanf("%d %d", &t1, &t2);k[t1].push_back(t2);k[t2].push_back(t1);}solve();dfs(1, 0);printf("%d", n-maxx);//本人代码量命名较随意见谅pu~
}

那么,这道题就用最暴力却细腻的处理解决了;

代码亮点在哪里?要怎么写?

  1. 分模块处理,即使只是简单的处理或回溯也不妨单独多出来一个函数方便进行相关的调试

  2. 理解题意并尽快找到dfs函数所需要传入的参数(例如本题就要尽快从常规方法将节点序号作为传入参数中脱离出来寻找新的做法

  3. 如果无法找到相关的关系,不妨进行一定量的预处理(例如本题中输入边未指明是父节点连向子节点或子节点连向父节点,而我只需要父节点连向子节点的相关边,就需要进行预处理即为单源最短路

  4. 提高思维的深度, 拓宽思维的宽度

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_103599.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【C++】了解设计模式、 stackqueue的使用与模拟实现

文章目录 1.设计模式2.stack1.stack的使用1.stack的结构2.stack的接口 2.stack的模拟实现1.stack的结构2.接口实现 3.queue1.queue的使用1.queue的结构3.queue的接口 2.queue的模拟实现1.queue的结构2.接口实现 4.了解deque1.deque的原理介绍2.deque的底层结构3.deque的迭代器设…

【Android入门到项目实战-- 7.1】—— 如何使用通知?

目录 一、创建通知的步骤 1、创建一个NotificationManager实例 2、使用一个Builder构造器来创建Notification对象 3、设置标题、文字、时间和图标等信息 4、显示通知 二、通知实例演示 三、实现通知的点击效果 1、PendingIntent 什么是PendingIntent&#xff1f; 如何使…

Linux下实现C语言程序

一.情况说明 写这篇博客的情况比较复杂&#xff0c;首先我本来是参加新星计划按照规划现在去学习shell脚本语言的&#xff0c;但是博主现在由于其他原因需要了解makefile&#xff0c;makefile是Linux系统下的一种工具&#xff0c;makefile的一些背景要涉及链接库的知识&#xf…

HTB-DevOops

HTB-DevOops 信息收集5000端口 立足python反序列化攻击XEE读取SSH root 信息收集 5000端口 根据文字所述&#xff0c;下面的图片是feed.py。 目录扫描 /upload如下&#xff1a; 上传测试xml文件。 得到反馈 怀疑是标签不匹配&#xff0c;尝试寻找匹配的标签。前面首页有提…

【算法】【算法杂谈】判断点是否在三角形内部(面积法和向量法)

目录 前言问题介绍解决方案代码编写java语言版本c语言版本c语言版本 思考感悟写在最后 前言 当前所有算法都使用测试用例运行过&#xff0c;但是不保证100%的测试用例&#xff0c;如果存在问题务必联系批评指正~ 在此感谢左大神让我对算法有了新的感悟认识&#xff01; 问题介…

Java企业电子招标采购系统源码Spring Boot + Mybatis + 前后端分离 构建企业电子招采平台之立项流程图

项目说明 随着公司的快速发展&#xff0c;企业人员和经营规模不断壮大&#xff0c;公司对内部招采管理的提升提出了更高的要求。在企业里建立一个公平、公开、公正的采购环境&#xff0c;最大限度控制采购成本至关重要。符合国家电子招投标法律法规及相关规范&#xff0c;以及…

HTB靶机-Lame-WP

Lame 简介&#xff1a; Lame is a beginner level machine, requiring only one exploit to obtain root access. It was the first machine published on Hack The Box and was often the first machine for new users prior to its retirement Tags&#xff1a; Injection, C…

OSCP-XPosedAPI(本地文件包含、查看源码、os.system、命令盲注)

目录 扫描 Web API枚举 命令盲注 提权 扫描 发现了两个开放的端口:端口22上的SSH和端口13337上的未知服务。 用netcat手动探测端口13337,但是运行几个常见的TCP/UDP服务初始化命令没有输出。 尝试了一个完整的脚本和版本nmap扫描的开放端口࿰

Vue+Echarts 项目演练(下)收尾工作图表绘制

设置销售总量图表 中心容器地图设置 产品库存统计图 产品类别图表 项目可视化完结-整体展示 设置销售总量图表 在第一个容器中进行图表设置 <template><div><h2>A</h2><div class"chart" id"oneChart">容纳后期的图表…

ChatGPT进化的过程简介

Chat GPT可以做什么&#xff1f; 分点列条的回答问题 写代码或SQL 翻译 语法检查 ChatGPT官方还未公开论文&#xff0c;ChatGPT有一个“孪生兄弟”InstructGPT&#xff0c;InstructGPT有论文&#xff0c;可以根据InstructGPT论文推导ChatGPT的训练过程&#xff1a; ChatGPT的…

MySQ基础知识整合

目录 模糊查询 排序 单行函数 多行函数 分组函数 having 单表查询执行顺序总结 distinct 连接查询 子查询 union limit DQL语句执行顺序 DDL语句 日期化 date和date_format区别 update table 的快速创建以及删除&#xff08;及回滚&#xff09; 约束 事务 …

Vector-常用CAN工具 - 入门到精通 - 专栏链接

一、CANoe篇 1、CANoe入门到精通_软件安装 2、CANoe入门到精通_硬件及环境搭建 3、CANoe入门到精通_软件环境配置 4、CANoe入门到精通_Network Node CAPL开发 5、CANoe入门到精通_Node节点开发基本数据类型 6、CANoe入门到精通_Test Node节点开发设置 7、CANoe入门到精通…

缩小数据文件

今天又出现12.2c 环境的问题&#xff0c;1T的数据空间还剩下2G&#xff0c;吓了一身冷汗&#xff0c;赶紧查看原因&#xff0c;不知道哪路业务大神作妖了。 发现sysaux和system增加N多数据文件&#xff0c;而且目前使用不多&#xff0c; 缩小表空间的数据文件 可以使用下面的语…

【python中的魔法方法有哪些?】

__init__(self, ...): 类的构造函数&#xff0c;用于创建一个类的实例并初始化它的属性。__str__(self): 返回对象的字符串表示形式&#xff0c;可以用于打印对象或者转化成字符串。__repr__(self): 返回对象的字符串表示形式&#xff0c;通常是用于开发者调试和查看对象信息。…

【FPGA-DSP】第九期:音频信号处理

从本文开始将记录一些简单的音频信号处理算法在System Generator中的实现方法。本文将介绍如何搭建音频信号的采集与输出模型。 音频信号属于一维信号&#xff0c;一些基本概念如下&#xff1a; 采样频率&#xff1a;根据奈奎斯特采样定理&#xff0c;采样频率Fs应该不低于声…

【C语言】基础语法5:数组和指针

上一篇&#xff1a;函数和递归 下一篇&#xff1a;字符串和字符处理 ❤️‍&#x1f525;前情提要❤️‍&#x1f525;   欢迎来到C语言基本语法教程   在本专栏结束后会将所有内容整理成思维导图&#xff08;结束换链接&#xff09;并免费提供给大家学习&#xff0c;希望…

记一次死锁问题

最近在做一个需求&#xff0c;碰到了死锁的问题&#xff0c;记录下解决问题的过程 背景 这个需求要改动一个接口&#xff0c;我这边称为A接口&#xff0c;原先的逻辑是A接口内部会调用c方法&#xff0c;c方法是一个dubbo方法&#xff0c; 现在需要再A接口里添加调用B方法&…

【ROS】ubuntu18.04安装ROS(ROS1 Melodic)

1、添加中科大ROS源 1.1、添加源 sudo sh -c . /etc/lsb-release && echo "deb http://mirrors.ustc.edu.cn/ros/ubuntu/ lsb_release -cs main" > /etc/apt/sources.list.d/ros-latest.list1. 2、添加公钥 sudo apt-key adv --keyserver hkp://keyser…

编译预处理

编译预处理 1、宏定义1.1、 无参宏定义1.2、使用宏定义的优点1.3、宏定义注意点1.4、带参数的宏(重点)1.5、条件编译1.6、宏定义的一些巧妙用法(有用)1.7、结构体占用字节数的计算原则&#xff08;考题经常考&#xff0c;要会画图&#xff09;1.8、#在宏定义中的作用&#xff0…

ESP32设备驱动-BMM150数字地磁传感器驱动

BMM150数字地磁传感器驱动 文章目录 BMM150数字地磁传感器驱动1、BMM150介绍2、硬件准备3、软件准备4、驱动实现1、BMM150介绍 BMM150 是一款低功耗、低噪声的 3 轴数字地磁传感器,用于罗盘应用。 具有 1.56 x 1.56 mm 和 0.60 mm 高度的 12 引脚晶圆级芯片级封装 (WLCSP) 为…