题意:

题目传送门

  • 在一棵 n 个结点的树上,有 k 个贪吃虫去吃食物。
  • 每个贪吃虫都走到达食物的唯一路径。
  • 当一条贪吃虫通向食物的道路上有另一条贪吃虫,则较远的那只停止移动。
  • 多条贪吃虫要进入同一节点时,编号最小的才能进入,其他的停止移动。
  • 贪吃虫的移动速度皆为 1。一只贪吃虫吃到食物后,另一个食物立刻出现在树上,贪吃虫继续按以上规则移动。
  • 最后求出每条贪吃虫所在的位置与吃到食物的数量。

思路:

可以把每一个食物看成一个测试点。那么就是要计算出每个节点被哪条贪吃虫占领和每条贪吃虫最终停留的地方。

很明显,对于这两个要计算的值,可以通过两次 dfs 来求。

第一次 dfs。对于每一个节点,占领它的贪吃虫一定是到达用时最短的那个。到达它的最短的时间就是最短的子节点到达时间 +1。还要注意两种特殊情况,在代码里也会有说明:

  1. 该点已有贪吃虫。

  2. 有速度相同,取编号最小的贪吃虫。

结束后把占领食物所在节点的贪吃虫吃到的食物数 +1。

第二次 dfs 时,可以利用第一次求出的值取计算。因为在第一次 dfs 时,我们求出了占领每个节点所用的时间,所以可以用一个数组去记录每一条贪吃虫到达最终落脚点的时间,这个值是可以算出的。如果对于某个节点,占据他的贪吃虫到达最终落脚点的时间 = 该节点被占领的时间,则该节点为这条贪吃虫的最终落脚点。

代码:

请勿抄袭。

#include<bits/stdc++.h>
using namespace std;
int n,k,h;
//n,k,h与题中含义一致
struct stu{
int nxt,to;
}e[10010];
int cnt;
int head[10010];
//以上为链式前向星存图
int b[5001];//每一条贪吃虫所在节点
int p[5001];//每个节点上为哪条贪吃虫,0表示没有贪吃虫
int c[501];//每一次食物出现的地方
int eat[5001];//每条贪吃虫吃的食物数
int t[5001];//占领每个节点的时间
int o[5001];//每个节点被占据的贪吃虫编号
int f[5001];//题解中第二次搜索用来记录的数组
inline void add(int x,int y)//建边
{
e[++cnt].nxt=head[x];
e[cnt].to=y;
head[x]=cnt;
}
inline void dfs1(int now,int fa)//第一次搜索,求出每个节点被哪条贪吃虫占据
//now为当前搜索到的节点,fa为上一次搜索的节点,避免重复搜索
{
int mp,mt;//记录占领该节点的时间与贪吃虫编号
if(p[now])//该点上已有贪吃虫
{
mp=p[now];//占领的贪吃虫即为该节点上的贪吃虫
mt=0;//占领速度为0
}
else //否则因为要取最小值,所以设一个大的数
{
mp=9999;
mt=9999;
}
for(int i=head[now];i;i=e[i].nxt)//依次搜索每一个儿子
{
int to=e[i].to;
if(to==fa) continue;//避免重复搜索
dfs1(to,now);
if((t[to]+1)<mt||((t[to]+1)==mt&&o[to]<mp))
//时间更短或时间相同并且编号较小即可更新
{
mt=t[to]+1;
mp=o[to];
}
}
t[now]=mt;
o[now]=mp;
//保存计算后的值
}
inline void dfs2(int now,int fa)//第二次搜索,计算每一只贪吃虫最终落脚点
//参数意义与dfs1一致
{
if(o[now]!=9999)//=9999说明没有贪吃虫来过,没必要计算
{
if(f[o[now]]==-1&&o[fa]!=o[now])
//没有计算过,后面的条件是因为贪吃虫一样,那么f[o[now]]没计算过,f[o[fa]]也一定没计算过
{ //计算,取三种可能时间的最小值
int mt=min(t[fa],t[now]);
f[o[now]]=min(f[o[fa]],mt);
}
if(f[o[now]]!=-1&&f[o[now]]==t[now]) b[o[now]]=now;//计算过且时间一致,则该点为这条贪吃虫的最终落脚点
}
for(int i=head[now];i;i=e[i].nxt)//继续搜索子节点
{
int to=e[i].to;
if(to==fa) continue;//同理,防重
dfs2(to,now);
}
}
int main()
{
scanf("%d",&n);
for(int i=1;i<n;i++)//读入这棵树,并建树(边)
{
int x,y;
scanf("%d%d",&x,&y);
add(x,y);
add(y,x);//建双向边
}
scanf("%d",&k);
for(int i=1;i<=k;i++)//记录每一条贪吃虫的位置
{
int x;
scanf("%d",&x);
p[x]=i;
b[i]=x;//按照数组含义记录
}
scanf("%d",&h);
for(int i=1;i<=h;i++)//读入每一次食物出现的位置
{
scanf("%d",&c[i]);
}
for(int i=1;i<=h;i++)
{
memset(t,0,sizeof(t));
memset(o,0,sizeof(o));
memset(f,-1,sizeof(f));//由于数组内还有上一次循环的值,因此将其初始化
dfs1(c[i],-1);//搜索
++eat[o[c[i]]];//将吃到食物的贪吃虫更新
f[o[c[i]]]=t[c[i]];//吃到食物的贪吃虫最终落脚点即为食物处
//因此到达最终落脚点的位置即为到达食物的位置
//这里也是为了下面的搜索的计算
dfs2(c[i],-1);
memset(p,0,sizeof(p));//由于这一轮过后贪吃虫又有了新的位置,因此先将旧的清零,并更新
for(int j=1;j<=k;j++)
{
p[b[j]]=j;
}
}
for(int i=1;i<=k;i++)//输出答案
{
printf("%d %d\n",b[i],eat[i]);
}
return 0;
}

写题解不易,点个赞呗。

P1751 贪吃虫 题解的更多相关文章

  1. 游戏:贪吃虫(GreedyMaggot)

    该游戏类似于贪吃蛇,但可以在二维平面上以任意方向前进.当吃到食物手,食物会从虫头向虫尾移动,移到虫尾后,贪吃虫长度会增加.本来给它取名为贪吃蛆的,并且工程的英文名Maggot就是蛆的意思,后来想想有点 ...

  2. 洛谷P7078 [CSP-S2020] 贪吃蛇 题解

    比赛里能做出这题的人真的非常厉害,至少他的智商和蛇一样足够聪明. 首先有一个结论: 当前最强的蛇吃了最弱的蛇之后,如果没有变成最弱的蛇,他一定会选择吃! 证明: 假设当前最强的蛇叫石老板. 如果下一条 ...

  3. Hadoop企业级应用

    Hadoop专业解决方案之构建Hadoop企业级应用 一.大数据的挑战 大数据面对挑战是你必须重新思考构建数据分析应用的方式.传统方式的应用构建是基于数据存储在不支持大数据处理的基础之上.这主要是因为 ...

  4. WhyEngine游戏合集2014贺岁版

    WhyEngine游戏合集2014贺岁版 自去年9月份开始写我的第一个小游戏,到现在为止,共实现了14个小游戏,10个屏保程序,7个DEMO程序.开发环境是VS2008,渲染使用的是D3D,所有代码都 ...

  5. Why游戏作品合集

    之前曾经发过一个套WhyEngine游戏作品合集,里面有十几个小游戏和若干个屏保程序和若干个DEMO程序.而这次发的与上次不一样,因为这是我花了两天时间将所有的程序集成到一个工程后的成果.为了能将所有 ...

  6. WhyEngine游戏引擎作品合集

    从9月份开始写三个月内总共实现了13个游戏,5个屏保程序,5个DEMO程序.如果运行时,报有木马病毒什么的,请相信我,这绝对是杀毒软件的误报,自己写的程序由于没有得到杀毒软件的认证,被报有危险是正常的 ...

  7. 【NOIp2004提高组】食虫算 题解

    所谓虫食算,就是原先的算式中有一部分被虫子啃掉了,需要我们根据剩下的数字来判定被啃掉的字母.来看一个简单的例子: 43#9865#045 + 8468#6633 44445509678 其中#号代表被 ...

  8. 【题解】 P1092虫食算

    [题解]P1092 虫食算 老题了,很经典. 用到了一些搜索套路. 可行性剪枝,劣者靠后,随机化,\(etc......\) 搜索设参也很有技巧,设一个\(adjustment\)参数可以很方便地在两 ...

  9. 【题解】ZJOI2010贪吃的老鼠

    %%%%真的好强...看题解我都看了好久才完全明白.放一下参考的博客,谢谢神犇QAQ 1号博客    2号博客(超级赞的啦) 因为理解的过程太艰辛,所以必须记录一下这道强题:这道题目最难的两个约束就在 ...

  10. NOIP 2004 虫食算题解

    问题 E: [Noip2004]虫食算 时间限制: 1 Sec  内存限制: 128 MB 题目描述 所谓虫食算,就是原先的算式中有一部分被虫子啃掉了,需要我们根据剩下的数字来判定被啃掉的字母.来看一 ...

随机推荐

  1. Java面试——Java基础

    更多内容,移步IT-BLOG 一.JAVA中的几种基本数据类型 Java语言中一共提供了8种原始的数据类型(byte,short,int,long,float,double,char,boolean) ...

  2. 使用 ApplicationContextAware 定义 SpringContextHolder 类

    需求:使用 @autowired注入一些对象,但发现不可以直接使用@Autowired,因为方法是static的,要使用该方法当前对象也必须是static,正常情况下@Autowired无法注入静态的 ...

  3. Maven常用依赖包简单

    Maven官方仓库:Maven Repository: junit » junit (mvnrepository.com) Mysql 1 <!--Mysql--> 2 <depen ...

  4. 手机号码归属地的自动查询.py(亲测有效)

    import requests url = "http://m.ip138.com/sj.asp?mobile=" kv = {'user-agent':'Mozilla/5.0' ...

  5. GLM:通用语言模型

    ChatGPT已经火了一段时间了,国内也出现了一些平替,其中比较容易使用的是ChatGLM-6B:https://github.com/THUDM/ChatGLM-6B ,主要是能够让我们基于单卡自己 ...

  6. 在IIS 搭建FTP站点

    最近在项目中需要用到FTP,需要将生成的文件通过FTP上传网站. 在此记录下. FTP SSL设置,需要允许SSL连接. FTP 身份验证,匿名身份验证需要启用. FTP 授权规则,如果没有特殊情况允 ...

  7. sqlplus文件查看oracle自带命令的执行过程

    问题描述:看到一篇文章 在$ORACLE_HOME/bin/sqlplus中可以查看到数据库命令的查询语句.可以直接编辑sqlplus文件,查到到我们平时标准系统命令的原脚本,但是自己进行编辑查看却是 ...

  8. C# 根据前台传入实体名称,动态查询数据

    前言: 项目中时不时遇到查字典表等数据,只需要返回数据,不需要写其他业务,每个字典表可能都需要写一个接口给前端调用,比较麻烦,所以采用下面这种方式,前端只需传入实体名称即可,例如:SysUser 1. ...

  9. Vue修改单页面背景颜色

  10. PyTorch基础(Numpy & Tensor)

    Numpy与Tensor是PyTorch的重要内容 Numpy的使用 Numpy是Python中科学计算的一个基础包,提供了一个多维度的数组对象,数组是由numpy.ndarray类来实现的,是Num ...