聪聪和可可

[https://www.luogu.com.cn/problem/P4206] (Luogu P4206)
思路:这题求的是期望,而且要两人足够聪明的情况下,聪聪先走,聪最多能走两步,所以他肯定是朝着可可的方向走两步。我们则可预处理出:Nxt[i][j]数组,表示i往j的方向走一步所到的点(即Nxt[i][j]在i->j的最短路上且与i相邻)。因为边权为1,所以用宽搜最快O(n+m),而我们确定下来他们每一步怎么走了,我们就可以写期望dp状态转移方程了:
dp[i][j] = ( sum{ dp[v][Nxt[j][v]] } + dp[i][Nxt[j][v]] ) * ( 1 / (size[i]+1) ) + 1

#include<stdio.h>
#include<bits/stdc++.h>
using namespace std;
const int N=1e3+5;
int nxt[N*2],X,Y,to[N*2],head[N],tot,inf=0x3f3f3f3f,Nxt[N][N];
int dis[N][N],size[N];	//[可可所在点][葱葱所在点] dp[i][j]=( sigma{ dp[v][Nxt[j][v]] } + dp[i][Nxt[j][v]] ) * ( 1 / (size[i]+1) ) + 1
double dp[N][N];
vector<int> G[N];
bool mark[N];
double MDP(int i,int j) {
	if(dp[i][j]!=-1) return dp[i][j];
	if(!dis[j][i]) return dp[i][j]=0.0;
	if(dis[j][i]<=2) return dp[i][j]=1.0;
	int T=Nxt[Nxt[j][i]][i];
	double sum=0;
	for(int k=0,sz=G[i].size();k<sz;k++) {
		int v=G[i][k];
		sum+=MDP(v,T);
	}
	sum+=MDP(i,T);
	dp[i][j] = sum * (1.0/(G[i].size()+1)) + 1;
	return dp[i][j];
}
queue<int>Q;
void BFS(int s) {
	memset(mark,false,sizeof(mark));
	Q.push(s);
	dis[s][s]=0; mark[s]=true; Nxt[s][s]=s;
	while(!Q.empty()) {
		int u=Q.front(); Q.pop();
		for(int i=0;i<G[u].size();i++) {
			int v=G[u][i];
			if(!mark[v]) {
				mark[v]=true;
				dis[s][v]=dis[s][u]+1;
				if(dis[s][v]==1) Nxt[s][v]=v;
				else Nxt[s][v]=Nxt[s][u];
				Q.push(v);
			}
		}
	}
}
int main() {
	int n,e;
	scanf("%d%d",&n,&e);
	scanf("%d%d",&X,&Y);
	for(int i=1;i<=e;i++) {
		int u,v;
		scanf("%d%d",&u,&v);
		G[u].push_back(v);
		G[v].push_back(u);
	}
	for(int i=1;i<=n;i++) {
		sort(G[i].begin(),G[i].end());
	}
	memset(dis,0x3f,sizeof(dis));
	for(int i=0;i<=n;i++) 
		for(int j=0;j<=n;j++) {
			dp[i][j]=-1.0;
		}
	for(int i=1;i<=n;i++) {
		BFS(i);
	}
	double ans=MDP(Y,X);
	printf("%.3lf",ans);
	return 0;
}

ps.别忘了字典序的问题哈