「NOI2005」聪聪和可可 题解

本文网址:https://www.cnblogs.com/zsc985246/p/16366661.html ,转载请注明出处。

题目大意

n 个点,m 条路的无向图,猫在 S 点,老鼠在 T 点,假设每个时间节点猫先走。猫每个时间节点可以靠近老鼠走两步(最短路),如果一步就可以抓到老鼠,就走一步,如果有多条最短路,选择节点标号小的一条;老鼠等概率地选择去向相邻的点或停留。

求猫捉到老鼠的期望时间(注意不是步数)

思路

dp 求期望。

考虑 dis[i][j] 表示猫在 i 点,老鼠在 j 点时,猫与老鼠间的距离,用 bfs 求解。

dp 做,所以定义 f[i][j] 表示猫在 i 老鼠在 j 的期望步数,则:

  • i=j ,即 dis[i][j]=0 直接可以抓到老鼠, f[i][j]=0

  • dis[i][j]2 ,即走一步就可以抓到老鼠, f[i][j]=1

  • dis[i][j]>2 ,不能在一次选择中抓到老鼠,那么她抓到老鼠的期望就与老鼠所做的选择有关了。

因为 E(ax+by)=a×E(x)+b×E(y) ,所以:

f[i][j]=1in[j]+1×f[x][j]+y(1in[j]+1×f[x][y])

in[i] 表示 i 连接的路的条数, 1in[j]+1 表示老鼠行动的概率, x 表示猫下一步的位置, y 表示老鼠下一步的位置。

第一坨表示老鼠停留时的期望,第二坨表示老鼠走时的期望

考虑到时间复杂度,使用记忆化搜索。

因此,代码出。

代码实现

#include<bits/stdc++.h>
#define ll int
const ll N=2020;
using namespace std;

ll n,m;
ll S,T;//猫和老鼠的起始点 
ll cnt,fir[N],nxt[N],v[N];//前向星 
ll in[N];//in[i]表示i连的边的条数 
ll dis[N][N];//dis[i][j]表示猫在i点,老鼠在j点时,猫与老鼠间的距离 
double f[N][N];//dp[i][j]表示猫在i老鼠在j的期望步数。
//不开double见祖宗!

void add(ll u1,ll v1){
	v[++cnt]=v1;
	nxt[cnt]=fir[u1];
	fir[u1]=cnt;
}

void bfs(ll s){//bfs求距离,s表示起点 
	queue<ll>q;
	q.push(s);
	while(!q.empty()){
		ll x=q.front();
		q.pop();
		for(ll i=fir[x];i;i=nxt[i]){
			if(!dis[s][v[i]]&&v[i]!=s){
				dis[s][v[i]]=dis[s][x]+1;
				q.push(v[i]);
			}
		}
	}
}

double dfs(ll s,ll t){//记忆化搜索,s表示猫的位置,t表示老鼠的位置 
	if(f[s][t])return f[s][t];
	if(dis[s][t]==0)return 0;//直接可以抓到老鼠 
	if(dis[s][t]<=2)return 1;//走一步就可以抓到老鼠 
	f[s][t]=1;
	ll k=N,tmp=s;//k表示最小编号,tmp表示猫的位置 
	
	//猫的行动 
	//走一步 
	for(ll i=fir[tmp];i;i=nxt[i]){
		if(dis[t][v[i]]<dis[tmp][t]&&v[i]<k){//距离小且编号小 
			k=v[i];
		}
	}
	tmp=k,k=N;
	//再走一步
	for(ll i=fir[tmp];i;i=nxt[i]){
		if(dis[t][v[i]]<dis[tmp][t]&&v[i]<k){
			k=v[i];
		}
	}
	tmp=k;
	
	//老鼠的行动 
	for(ll i=fir[t];i;i=nxt[i]){
		f[s][t]+=1.0/(in[t]+1)*dfs(tmp,v[i]);//公式第二坨 
	}
	f[s][t]+=1.0/(in[t]+1)*dfs(tmp,t);//公式第一坨 
	return f[s][t];
}

int main(){
	
	scanf("%d%d",&n,&m);
	scanf("%d%d",&S,&T);
	for(ll i=1;i<=m;i++){
		ll u1,v1;
		scanf("%d%d",&u1,&v1);
		add(u1,v1),add(v1,u1);
		in[u1]++,in[v1]++;
	}
	for(ll i=1;i<=n;i++)bfs(i);
	printf("%.3lf\n",dfs(S,T));
	
	return 0;
}

尾声

如果你发现了问题,你可以直接回复这篇题解

如果你有更好的想法,也可以直接回复!

posted @   zsc985246  阅读(192)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示