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

  

posted @ 2019-10-31 20:44  EM-LGH  阅读(132)  评论(0编辑  收藏  举报