[NOI2005]聪聪与可可

XII.[NOI2005]聪聪与可可

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

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

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

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

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

则有:

\(f_{i,j}=0\),如果\(i=j\)

\(f_{i,j}=1\),如果猫能直接从\(i\)走到\(j\)

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

\[f_{i,j}=\dfrac{f_{nex2_{i,j},j}\sum f_{nex2_{i,j},k}}{deg_k+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;
} 

原文地址:https://www.cnblogs.com/Troverld/p/14610986.html