P1751 贪吃虫
因为小虫全部向着食物移动,如果没有前往食物的路径就不移动。
不难想到可以从糖果位置开始搜索。
第一次先搜索出哪些地方有小虫。
如果找到了小虫,那么停止遍历,将这个点的虫子编号和距离记录下来,距离设为 \(0\) 作为起始点。
之后把这只小虫的状态转移会上一步,距离加一,如果有多个虫子,选择距离小的,因为距离小的用时更短,若距离相同,则选择编号小的。
记录下距离和虫子可以方便我们下一步将小虫移动到正确位置。
本部分搜索:
void dfs(int x,int fa){
if(t[x]){//表示图上x点的虫子
dis[x]=0;
b[x]=t[x];//表示x上虫子编号
}
for(int i:e[x]){
if(i==fa)continue;
dfs(i,x);
if(dis[i]+1<dis[x]||dis[i]+1==dis[x]&&b[i]<b[x]){
dis[x]=dis[i]+1;//转移
b[x]=b[i];
}
}
}
之后对于小虫位置进行转移。
我们不仅储存了距离,还可以用距离来推出时间。
如果出现两个相连的点,属于两只不同的虫子,由于我们从食物点开始搜索,则我们必定是从耗时短的虫子到时间长的虫子。
那么如果这一点耗时短,直接用这个耗时覆盖下一个点,如果相同,则相同时小虫已经到达了被阻挡时的位置,将小虫位置设为此点,继续搜索即可。
注意将开始时的小虫位置设置为食物位置。
二次搜索代码:
void dfs2(int x,int fa){
if(!b[x])return;
if(b[x]!=b[fa]&&dis[x]>dis[fa]){
b[x]=b[fa];
dis[x]=dis[fa];
}
else if(b[x]!=b[fa]){
t[x]=b[x];
w[b[x]]=x;
}
for(int i:e[x]){
if(i==fa)continue;
dfs2(i,x);
}
}
Code:
#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,k,t[5005],w[1005],dis[5005],ans[1005],b[5005],h;
vector<int> e[5005];
void dfs(int x,int fa){//第一步处理小虫前进方向
if(t[x]){
dis[x]=0;
b[x]=t[x];
}
for(int i:e[x]){
if(i==fa)continue;
dfs(i,x);
if(dis[i]+1<dis[x]||dis[i]+1==dis[x]&&b[i]<b[x]){
dis[x]=dis[i]+1;
b[x]=b[i];
}
}
}
void dfs2(int x,int fa){//第二步处理小虫移动到的位置
if(!b[x])return;
if(b[x]!=b[fa]&&dis[x]>dis[fa]){
b[x]=b[fa];
dis[x]=dis[fa];
}
else if(b[x]!=b[fa]){
t[x]=b[x];
w[b[x]]=x;
}
for(int i:e[x]){
if(i==fa)continue;
dfs2(i,x);
}
}
signed main(){
cin>>n;
for(int i=1,x,y;i<n;i++){
cin>>x>>y;
e[x].push_back(y);
e[y].push_back(x);
}
cin>>k;
for(int i=1,x;i<=k;i++){
cin>>x;
t[x]=i;//树上节点x的小虫
w[i]=x;//第i只小虫的位置设置为x
}
cin>>h;
int x;
while(h--){
cin>>x;
memset(dis,0x3f,sizeof(dis));
memset(b,0,sizeof(b));//初始化距离和小虫途径
dfs(x,0);
memset(t,0,sizeof(t));//小虫位置初始化
ans[b[x]]++;//增加小虫吃到的食物数量
dfs2(x,0);
}
for(int i=1;i<=k;i++)cout<<w[i]<<' '<<ans[i]<<endl;//输出答案
return 0;
}

浙公网安备 33010602011771号