题意:

题目传送门

  • 在一棵 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. MySQL 慢查询优化案例

    一.慢查询优化基本步骤 [1]先运行看看是否真的很慢,注意设置SQL_NO_CACHE(查询时不使用缓存):[2]where条件单表查,锁定最小返回记录表.这句话的意思是把查询语句的 where都应用 ...

  2. Zab(Zookeeper Atomic Broadcast)协议

    更多内容,前往IT-BLOG 一.什么是 Zab协议 Zab( Zookeeper Atomic Broadcast:Zookeeper原子广播)Zookeeper 通过 Zab 协议保证分布式事务的 ...

  3. 宝塔上部署FastAPI的步骤和一些注意点

    为了运维方便,选择直接用宝塔来管理python fastapi的项目,虽然直接部署可能性能更好更灵活,但是我选择了低层本,每个人的选择可能是不一样的,各有 考虑吧. 本文的大逻辑是先写一个hellow ...

  4. 3d基础 - 从模型坐标到屏幕坐标

    在 3D 引擎中,场景通常被描述为三维空间中的模型或对象,每个模型对象由许多三维顶点组成.最终,这些模型对象将在平面屏幕上呈现和显示. 渲染场景始终相对于摄像机,因此,还必须相对于摄像机的视图定义场景 ...

  5. Nginx主要功能

    Nginx主要功能: 1.反向代理2.负载均衡3.HTTP服务器(包含动静分离)4.正向代理 一.反向代理 反向代理应该是 Nginx 做的最多的一件事了,什么是反向代理呢,以下是百度百科的说法:反向 ...

  6. [Java]算法练习:新农村建设

    1 题目描述 from 网友 CASE1 输入 A1 A8 输出 [A1,A2,A3,A4,A5,A6,A7,A8] CASE2 输入 A1 K1 输出 [A1,B1,C1,D1,E1,F1,G1,H ...

  7. 第一章 static、单例与继承

    目录 面向对象 一.static关键字 1.static修饰成员变量 2.static修饰成员变量内存中执行原理 3.成员方法的执行原理 4.工具类 5.静态关键字注意事项 6.代码块 java静态代 ...

  8. 粘包,自定义协议,struct模块,粘包解决终极大招

    粘包: 1.粘包问题出现的原因: (udp不会出现粘包问题) 1.1.tcp是流式协议,数据像水流一样黏在一起,没有任何边界区分 1.2.收数据没收干净,有残留,就会下一次结果混淆在一起去(客户端接受 ...

  9. Python实现网络工具

    使用python编写网络工具 基础内容 介绍基本的网络编程 Socket编程 Socket又称"套接字",应用程序通常通过"套接字"向网络发出请求或者应答网络请 ...

  10. AndroidApp加固与脱壳

    0x01 APP加固 01.为什么要加固 APP加固是对APP代码逻辑的一种保护.原理是将应用文件进行某种形式的转换,包括不限于隐藏,混淆,加密等操作,进一步保护软件的利益不受损坏.总结主要有以下三方 ...