BZOJ1415 聪聪和可可

BZOJ1415 聪聪和可可

期望Dp

题解:

f[i][j] 表示聪聪在点i,可可在点j时的期望步数。

  • i==j时, f[i][j]=0
  • i按找要求走一步或两步能走到j时, f[i][j]=1
  • 否则:
    f[i][j]=f[i][j]+1+(f[i][j]+1)du[j]+1

    i’是i按照要求走两步后的点,j’是与j相连的点。

对了多说一句,它满足无后效性,就是两点之间的距离会越来越近。记忆化搜索即可。

Code:

#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue> 
#define MP make_pair
using namespace std;
const int N = 1005;

int n,m,du[N],path[N][N]; 
double f[N][N]; 
bool vis[N]; int dis[N][N];

struct Edge{
    int to,next;
} e[N*2];
int head[N], ec; 
void add(int a,int b){
    ec++; e[ec].to=b; e[ec].next=head[a]; head[a]=ec;
}

void bfs(int S){
    memset(vis,false,sizeof(vis));
    queue<int> q; vis[S]=true; dis[S][S]=0; q.push(S); 
    while(!q.empty()){
        int u=q.front(); q.pop();
        for(int i=head[u];i;i=e[i].next){
            int v=e[i].to; 
            if(!vis[v]){ 
                vis[v]=true; dis[S][v]=dis[S][u]+1; q.push(v); 
            }
        }
    }
}

double dp(int i,int j){
    double &ans=f[i][j];
    if(ans>-0.1) return ans;  //ans>=0
    if(i==j) return ans=0;
    int ii=path[i][j]; if(ii==j) return ans=1;
    ii=path[ii][j]; if(ii==j) return ans=1;
    ans=0; ans+=(dp(ii,j)+1)/(du[j]+1);
    for(int tp=head[j];tp;tp=e[tp].next){
        int jj=e[tp].to;
        ans+=(dp(ii,jj)+1)/(du[j]+1);
    }
    return ans;
}

int main(){
    freopen("a.in","r",stdin);
    int cc,kk,a,b;
    scanf("%d%d%d%d",&n,&m,&cc,&kk);
    for(int i=1;i<=m;i++){
        scanf("%d%d",&a,&b);
        add(a,b); add(b,a);
        du[a]++; du[b]++;
    }
    for(int i=1;i<=n;i++) bfs(i);
    for(int u=1;u<=n;u++){
        for(int v=1;v<=n;v++){
            path[u][v]=u;
            for(int i=head[u];i;i=e[i].next){
                int p=e[i].to;
                if(dis[p][v]<dis[path[u][v]][v] || (dis[p][v]==dis[path[u][v]][v] && p<path[u][v]))
                    path[u][v]=p;
            }
        }
    } 
    for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) f[i][j]=-1;
    printf("%.3f\n",dp(cc,kk));
}

感谢mengcier订正

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值