P4206 [NOI2005] 聪聪与可可 题解

Sol

你会发现在一个时刻,聪聪走到哪里是固定的,所以我们从这里入手。

我们考虑预处理 \(nxt_{i,j}\) 表示聪聪在 \(i\),可可在 \(j\) 时,聪聪下一步的位置。

如果我们把 \(i \to j\) 的路径扣出来,时间复杂度是 \(O(n^3)\) 的,需要优化。

我们可以跑 \(n\) 次 BFS,把任意两点 \(x,y\) 的距离 \(dis_{x,y}\)\(O(n^2)\) 的时间求出。

这样的话,求出所以 \(nxt_{i,j}\) 的总时间复杂度就是 \(O(\eta n^2)\) 的了,\(\eta\) 是枚举 \(i\)\(2\) 步到达的点所花的时间,随机数据下接近于 \(2\)

接下来我们考虑求答案,我们设 \(dp_{i,j}\) 表示聪聪在 \(i\),可可在 \(j\) 的回合数的期望,转移分 \(3\) 种情况:

  • 这回合什么也不用干就结束,即 \(i=j\) 时,期望为 \(0\)
  • 这回合可可不需要移动就结束,即 \(dis_{i,j} \le 2\) 是,期望为 \(1\)
  • 这回合可可需要移动,那么聪聪肯定会固定移动到 \(nxt_{i,j}\),接下来要讨论的是可可的移动,可可会等概率地移动到他可移动到的位置,即 \(dp_{i,j}=1 + \sum\limits_{j \to j'}dp_{nxt_{i,j},j'}(\frac{1}{du_j+1})\)

由于转移顺序相对复杂,所以我们考虑记忆化搜索,时间复杂度 \(O(n^2)\)

总时间复杂度 \(O(\eta n^2)\)

Code

#include<bits/stdc++.h>
using namespace std;
#define int long long 

const int N=1005;
int n,m,st,ed,nxt[N][N],dis[N][N],ls[N][N],du[N];
double dp[N][N];
vector<int>nbr[N];

void bfs(int s)
{
	queue<int>q;
	q.push(s);
	dis[s][s]=0;
	while(q.empty()==false)
	{
		int cur=q.front();
		q.pop();
		for(int nxt:nbr[cur])
			if(dis[s][nxt]>1e13)
			{
				dis[s][nxt]=dis[s][cur]+1;
				q.push(nxt);
			}
	}
	return ;
}

double M_dfs(int cc,int kk)
{
	if(cc==kk)
		return 0;
	if(dis[cc][kk]<=2)
		return 1;
	if(dp[cc][kk]!=0)
		return dp[cc][kk];
	double gl=1.0/du[kk];
	int than=nxt[cc][kk];
	dp[cc][kk]=M_dfs(than,kk)*gl+1;
	for(int p:nbr[kk])
		dp[cc][kk]+=M_dfs(than,p)*gl;
	return dp[cc][kk];
}

signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	cin>>n>>m>>st>>ed;
	for(int i=1;i<=m;i++)
	{
		int x,y;
		cin>>x>>y;
		nbr[x].push_back(y);
		nbr[y].push_back(x);
		du[x]++,du[y]++;
	}
	memset(dis,0x3f,sizeof dis);
	for(int i=1;i<=n;i++)
	{
		bfs(i);
		du[i]++;
	}
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++)
		{
			if(dis[i][j]<=2)
			{
				nxt[i][j]=j;
				continue;
			}
			for(int k:nbr[i])
				for(int p:nbr[k])
				{
					if(p==i)
						continue;
					if(dis[nxt[i][j]][j]>dis[p][j])
						nxt[i][j]=p,ls[i][j]=k;
					else if(dis[nxt[i][j]][j]==dis[p][j]&&k<ls[i][j])
						nxt[i][j]=p,ls[i][j]=k;
					else if(dis[nxt[i][j]][j]==dis[p][j]&&k==ls[i][j]&&p<nxt[i][j])
						nxt[i][j]=p,ls[i][j]=k;
				}
		}
	// for(int i=1;i<=n;i++)
	// {
	// 	for(int j=1;j<=n;j++)
	// 		cerr<<nxt[i][j]<<" ";
	// 	cerr<<"\n";
	// }
	cout<<fixed<<setprecision(3)<<M_dfs(st,ed);
	return 0;
}
posted @ 2025-04-12 10:25  tmp_get_zip_diff  阅读(16)  评论(0)    收藏  举报