ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

「NOI2005」聪聪和可可 题解

2022-06-11 20:00:32  阅读:146  来源: 互联网

标签:表示 老鼠 期望 题解 ll NOI2005 聪聪 fir dis


「NOI2005」聪聪和可可 题解

题目大意

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

求猫捉到老鼠的期望时间。

输入

第1行:n,m

第2行:S,T

接下来m行:u,v,表示u和v之间有一条路。

输出

猫捉到老鼠的期望时间。

思路

初始想法

一眼扫过题目,“期望”二字格外显目。又因为是图,所以可以考虑 $ 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] \le 2 $ ,即走一步就可以抓到老鼠, $ f[i][j]=1 $ ;

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

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

$ f[i][j]= \frac{1}{in[j]+1} \times f[x][j] + \underset y \sum (\frac{1}{in[j]+1} \times f[x][y]) $

$ in[i] $ 表示 $ i $ 连接的路的条数, $ \frac{1}{in[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);//bfs求距离 
	printf("%.3lf\n",dfs(S,T));//dfs求答案 
	
	return 0;
}

尾声

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

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

标签:表示,老鼠,期望,题解,ll,NOI2005,聪聪,fir,dis
来源: https://www.cnblogs.com/zsc985246/p/16366661.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有