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;
}
posted @ 2025-10-31 09:03  huhangqi  阅读(3)  评论(0)    收藏  举报
/*
*/