[NOI2005]聪聪与可可

XII.[NOI2005]聪聪与可可

这题一个naive的思路是设pi,j表示i时刻老鼠在位置j的概率,然后求出fi表示猫i时刻前抓到老鼠的概率(因为如果i时刻猫可以抓到老鼠,则i+1时刻猫一定仍可以抓到老鼠;而i时刻猫能抓到老鼠的位置只有可能距猫的起点2i),最后差个分就能得出答案。

但是我们发现猫并不能保证所有2i的位置都能抓到——举例子来说,我们有这样一个样例:

猫从1出发,第一时刻到达3;但是,如果老鼠此时走到了5,虽然15的距离2i=2,但是猫仍不能一次抓到老鼠。

所以我们不得不考虑一种新的想法,即记录下猫和鼠的位置,求出此时它期望多少轮能够捉到鼠。

我们设fi,j表示猫在i时,鼠在j时的期望次数;我们再设nex2i,j表示此时猫下一步会走到哪里。nex2可以通过O(nm)地预处理出来距离数组,再O(nm)地预处理出来nex1数组表示猫走一步的目标,然后通过nex1预处理出来nex2得出。

则有:

fi,j=0,如果i=j

fi,j=1,如果猫能直接从i走到j

否则,设这里有一条边(j,k),则有

fi,j=fnex2i,j,jfnex2i,j,kdegk+1

凭直觉发现这不可能有环;故直接记忆化搞掉即可。

时间复杂度O(nm)

代码:

#include<bits/stdc++.h>
using namespace std;
int n,m,dis[1010][1010],nex1[1010][1010],nex2[1010][1010],cat,mouse;
double f[1010][1010];
bool vis[1010][1010];
vector<int>v[1010];
void bfs(int S){
	queue<int>q;
	memset(dis[S],0x3f,sizeof(dis[S])),dis[S][S]=0;
	q.push(S);
	while(!q.empty()){
		int x=q.front();q.pop();
		for(auto y:v[x])if(dis[S][y]==0x3f3f3f3f)dis[S][y]=dis[S][x]+1,q.push(y);
	}
}
double dfs(int x,int y){
	if(vis[x][y])return f[x][y];
	vis[x][y]=true;
	double &now=f[x][y];
	if(x==y)return now=0;
	if(nex2[x][y]==-1)return now=1;
	x=nex2[x][y];
	for(auto z:v[y])now+=dfs(x,z)+1;
	now+=dfs(x,y)+1;
	now/=int(v[y].size()+1);
	return now;
}
int main(){
	scanf("%d%d",&n,&m);
	scanf("%d%d",&cat,&mouse);
	for(int i=1,x,y;i<=m;i++)scanf("%d%d",&x,&y),v[x].push_back(y),v[y].push_back(x);
	for(int i=1;i<=n;i++)bfs(i);
//	for(int i=1;i<=n;i++){for(int j=1;j<=n;j++)printf("%d ",dis[i][j]);puts("");}
	for(int i=1;i<=n;i++)for(int j=1;j<=n;j++){
		if(dis[i][j]==0x3f3f3f3f)continue;
		if(dis[i][j]<=1){nex1[i][j]=-1;continue;}
		int mp=-1;
		for(auto k:v[i])if(mp==-1||dis[mp][j]>dis[k][j]||dis[mp][j]==dis[k][j]&&mp>k)mp=k;
		nex1[i][j]=mp;
	}
	for(int i=1;i<=n;i++)for(int j=1;j<=n;j++){
		if(dis[i][j]==0x3f3f3f3f)continue;
		if(nex1[i][j]==-1||nex1[nex1[i][j]][j]==-1){nex2[i][j]=-1;continue;}
		nex2[i][j]=nex1[nex1[i][j]][j]; 
	}
//	for(int i=1;i<=n;i++){for(int j=1;j<=n;j++)printf("%d ",nex2[i][j]);puts("");}
//	for(int i=1;i<=n;i++)printf("%d ",dis[i]);puts("");
	printf("%.3lf\n",dfs(cat,mouse));
	return 0;
} 

posted @   Troverld  阅读(59)  评论(0编辑  收藏  举报
编辑推荐:
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?
点击右上角即可分享
微信分享提示