NOI 2005 聪聪和可可 [期望DP]
一个连通的图上有一只猫和老鼠,猫每次能移动一步,会选择到老鼠的最短路去移动,如果有多个选择,移动到标号最小的一个点。如果一步没有抓到老鼠的话,猫可以连续继续移动一步。接着老鼠会随机移动到他附近的一个点或者留在原地,每种移动的概率是1/(该点的度+1)。求猫平均几次可以抓到老鼠。
p[i][j]表示猫在i老鼠在j猫下一步会选择的点,对每个点bfs一遍可以预处理出来。f[i][j]表示猫在i,老鼠在j猫抓到老鼠的期望,则有
f[i,i]=0,p[i,j]==j或者p[p[i,j],j]==j时f[i][j]=1。
1 #include <string.h> 2 #include <stdio.h> 3 #define MAXN 1005 4 struct edge{ 5 int v,n; 6 }e[MAXN*2]; 7 int first[MAXN],es; 8 int n,m,c1,c2,tu,tv; 9 int p[MAXN][MAXN],deg[MAXN]; 10 double d[MAXN][MAXN]; 11 void addedge(int u,int v){ 12 deg[u]++,e[es].v=v,e[es].n=first[u],first[u]=es++; 13 } 14 int vis[MAXN],q[MAXN],front,rear; 15 void bfs(int s){ 16 memset(vis,-1,sizeof vis);vis[s]=0; 17 q[front=rear=0]=s,rear++; 18 while(front<rear){ 19 int u=q[front++]; 20 for(int i=first[u];i!=-1;i=e[i].n){ 21 int v=e[i].v; 22 if(vis[v]==-1)vis[v]=vis[u]+1,q[rear++]=v,p[v][s]=u; 23 else if(vis[v]==vis[u]+1&&p[v][s]>u)p[v][s]=u; 24 } 25 } 26 } 27 double dp(int c1,int c2){ 28 if(d[c1][c2])return d[c1][c2]; 29 if(c1==c2)return 0.0; 30 if(p[p[c1][c2]][c2]==c2||p[c1][c2]==c2)return 1.0; 31 double tmp=dp(p[p[c1][c2]][c2],c2); 32 for(int i=first[c2];i!=-1;i=e[i].n) 33 tmp+=dp(p[p[c1][c2]][c2],e[i].v); 34 return d[c1][c2]=tmp/(deg[c2]+1)+1; 35 } 36 int main(){ 37 while(scanf("%d%d",&n,&m)!=EOF){ 38 scanf("%d%d",&c1,&c2); 39 memset(deg,0,sizeof deg); 40 memset(first,-1,sizeof first);es=0; 41 for(int i=0;i<m;i++){ 42 scanf("%d%d",&tu,&tv); 43 addedge(tu,tv); 44 addedge(tv,tu); 45 } 46 for(int i=1;i<=n;i++) 47 for(int j=1;j<=n;j++)p[i][j]=d[i][j]=0; 48 for(int i=1;i<=n;i++)bfs(i); 49 printf("%.3f\n",dp(c1,c2)); 50 } 51 return 0; 52 }