bzoj 1415: [Noi2005]聪聪和可可 期望dp+记忆化搜索
期望dp水题~
你发现每一次肯定是贪心走 2 步,(只走一步的话就可能出现环)
然后令 $f[i][j]$ 表示聪在 $i$,可在 $j$,且聪先手两个人碰上面的期望最小次数.
用记忆化搜索转移就行了.
code:
#include <queue> #include <cstdio> #include <vector> #include <cstring> #include <algorithm> #define N 1004 #define LL long long #define pb push_back #define setIO(s) freopen(s".in","r",stdin) using namespace std; int n,m; queue<int>q; vector<int>G[N]; double dp[N][N]; int nxt[N][N],dis[N][N],vis[N],d[N],vised[N][N]; double f(int a,int b) { if(a==b) return 0.0; if(nxt[a][b]==b) return 1.00; if(nxt[nxt[a][b]][b]==b) return 1.00; if(vised[a][b]) return dp[a][b]; vised[a][b]=1; dp[a][b]=0.000; for(int i=0;i<G[b].size();++i) { int v=G[b][i]; dp[a][b]+=(f(nxt[nxt[a][b]][b], v)+1.00)/(double)G[b].size(); } return dp[a][b]; } int main() { int i,j,A,B; scanf("%d%d%d%d",&n,&m,&A,&B); for(i=1;i<=m;++i) { int a,b; scanf("%d%d",&a,&b); G[a].pb(b),G[b].pb(a); } for(i=1;i<=n;++i) { memset(vis,0,sizeof(vis)); d[i]=0; q.push(i); vis[i]=1; while(!q.empty()) { int u=q.front(); q.pop(); for(j=0;j<G[u].size();++j) { int v=G[u][j]; if(!vis[v]) { vis[v]=1; d[v]=d[u]+1; q.push(v); } } } nxt[i][i]=i; for(j=1;j<=n;++j) { if(j==i) continue; int mx=0,k,v; for(k=0;k<G[j].size();++k) { v=G[j][k]; if(d[j]==d[v]+1&&(v<mx||!mx)) mx=v; } nxt[j][i]=mx; } } for(i=1;i<=n;++i) G[i].pb(i); printf("%.3f\n",f(A,B)); return 0; }