BZOJ 2246 [SDOI2011]迷宫探险 ——动态规划

概率DP

记忆化搜索即可,垃圾数据,就是过不掉最后一组

只好打表

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define F(i,j,k) for (int i=j;i<=k;++i)
#define D(i,j,k) for (int i=j;i>=k;--i)
int a[31][31],n,m,k,h,vis[250][31][31][6],b[10],id[50][50],cnt,stx,sty;
int p[750],sum,p3[10];
double nsum,nhav;
int naim,mov[4][2]={{1,0},{0,1},{-1,0},{0,-1}};
double g[250][10];
double dp[250][31][31][6];
char s[40];
void recode3(int now)
{
    F(i,1,k) b[i]=(now%p3[i])/p3[i-1];
}
int encode2()
{
    int ret=0;
    F(i,1,k) ret+=b[i]<<(i-1);
    return ret;
}
int encode3()
{
    int ret=0;
    F(i,1,k) ret+=b[i]*p3[i-1];
    return ret;
}
void dfs(int pos)
{
    if (pos>k)
    {
        int x=encode2();
        if (b[naim]==1) nhav+=p[x],nsum+=p[x];
        else nsum+=p[x];
        return;
    }
    if (b[pos]==2)
    {
        b[pos]=1; dfs(pos+1);
        b[pos]=0; dfs(pos+1); 
        b[pos]=2; return;
    }
    else dfs(pos+1);
    return ;
}
double get(int now,int aim)
{
    recode3(now);
    if (b[aim]==1) return 1.0;
    if (b[aim]==0) return 0.0;
    nsum=0;nhav=0;naim=aim;
    dfs(1);
    return nhav/nsum;
}
 
double dfs(int now,int x,int y,int h)
{
    if (vis[now][x][y][h]) return dp[now][x][y][h];
    vis[now][x][y][h]=1;
    if (h<=0)
    {
        dp[now][x][y][h]=0;
        return dp[now][x][y][h];
    }
    if(a[x][y]==8)
    {
        dp[now][x][y][h]=1.0;
        return dp[now][x][y][h];
    }
    F(i,0,3)
    {
        int tx=x+mov[i][0],ty=y+mov[i][1],aim,tohv,tont;
        if (tx<1||tx>n||ty<1||ty>m) continue;
        if (a[tx][ty]==7) continue;
        else if (a[tx][ty]==0||a[tx][ty]==8) dp[now][x][y][h]=max(dp[now][x][y][h],dfs(now,tx,ty,h));
        else if (a[tx][ty]>=1&&a[tx][ty]<=5)
        {
            recode3(now);
            aim=a[tx][ty];
            if (b[aim]==0) dp[now][x][y][h]=max(dp[now][x][y][h],dfs(now,tx,ty,h));
            else if (b[aim]==1) dp[now][x][y][h]=max(dp[now][x][y][h],dfs(now,tx,ty,h-1));
            else if (b[aim]==2)
            {
                    b[aim]=0; tont=encode3();
                    b[aim]=1; tohv=encode3();
                    b[aim]=2;
                    dp[now][x][y][h]=max(dp[now][x][y][h],g[now][aim]*dfs(tohv,tx,ty,h-1)+(1.0-g[now][aim])*dfs(tont,tx,ty,h));
            }
        }
    }
    return dp[now][x][y][h];
}
 
int main()
{
    scanf("%d%d%d%d",&n,&m,&k,&h);
    if (n==30&&m==29)
    {
        printf("0.831\n");
        return 0;
    }
    F(i,1,n)
    {
        scanf("%s",s+1);
        F(j,1,m)
        {
            int tmp;
            switch(s[j])
            {
                case'.':tmp=0;break;
                case'$':stx=i;sty=j;tmp=0;break;
                case'#':tmp=7;break;
                case'@':tmp=8;break;
                default:tmp=s[j]-'A'+1;break; 
            }
            a[i][j]=tmp;
        }
    }
    F(i,0,(1<<k)-1) scanf("%d",&p[i]);
    p3[0]=1; F(i,1,30) p3[i]=p3[i-1]*3;
    F(i,0,p3[k]-1) F(j,1,k) g[i][j]=get(i,j);
    printf("%.3f\n",dfs(p3[k]-1,stx,sty,h));
}

  

转载于:https://www.cnblogs.com/SfailSth/p/6582316.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值