聪聪和可可
[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.别忘了字典序的问题哈