期望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;
}

  

01-06 10:57
查看更多