P2489 [SDOI2011]迷宫探险 概率dp
Posted chdy
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P2489 [SDOI2011]迷宫探险 概率dp相关的知识,希望对你有一定的参考价值。
LINK:迷宫探险
题目中要求在最优的策略下的最大概率 而并非期望概率。
一个坑点 题目中虽然没有明说 但是 探险者是知道地图的模样和每个陷阱的概率的。
所以才有最优策略一说。
最优策略尽管不知道可以随便走取max即可。
容易想到 对于当前状态 有 x,y,hp,s 来描述 。倒着设状态 那就是当前状态能到达终点的最大概率。
定义hp s都是递增的 不过还是不能线性递推。存在问题 可能状态之间可以互相转移的问题。
显然状态转移回来是不必要的 所以此时概率为0 利用dfs栈可以很容易判断出来 所以考虑记忆化搜索。
不过这引出了另外一个问题 当前状态可能被多次访问到 不过当前状态被第一次访问到已经被标记了 此时可能不是最优的。
容易想到转移到当前状态最多只有4种可能都记录下来即可。
//偷税吧 少年
const int MAXN=32,N=244;
int n,m,H,k,maxx,s1,s2,maxx1,ans;
int w[1<<5],b[N];
int vis[MAXN][MAXN][6][N][5];
db g[N][6],f[MAXN][MAXN][6][N][5];//f[i][j][k][s]表示当前到了i,j Hp为k 陷阱的状态为k能逃出去的最大概率.
char a[MAXN][MAXN];
int dx[4]={1,-1,0,0};
int dy[4]={0,0,-1,1};
inline db dp(int x,int y,int hp,int s,int op)
{
if(vis[x][y][hp][s][op])return f[x][y][hp][s][op];
vis[x][y][hp][s][op]=1;
if(hp==0)return f[x][y][hp][s][op]=0;
if(a[x][y]==‘@‘)return f[x][y][hp][s][op]=1;
db ans=0;
rep(0,3,i)
{
int xx=x+dx[i];
int yy=y+dy[i];
if(xx<=0||xx>n||yy<=0||yy>m)continue;
if(a[xx][yy]==‘#‘)continue;
if(a[xx][yy]==‘.‘||a[xx][yy]==‘$‘||a[xx][yy]==‘@‘)ans=max(ans,dp(xx,yy,hp,s,i));
else
{
int ww=a[xx][yy]-‘A‘+1;
if(s/b[ww-1]%3==0)
ans=max(ans,dp(xx,yy,hp-1,s+b[ww-1],i)*g[s][ww]
+dp(xx,yy,hp,s+b[ww-1]*2,i)*(1-g[s][ww]));
if(s/b[ww-1]%3==1)ans=max(ans,dp(xx,yy,hp-1,s,i));
if(s/b[ww-1]%3==2)ans=max(ans,dp(xx,yy,hp,s,i));
}
}
return f[x][y][hp][s][op]=ans;
}
int main()
{
freopen("1.in","r",stdin);
gt(n);gt(m);gt(k);gt(H);
rep(1,n,i)
{
gc(a[i]);
rep(1,m,j)if(a[i][j]==‘$‘)s1=i,s2=j;
}
maxx=1<<k;--maxx;b[0]=1;
rep(0,maxx,i)get(w[i]),ans+=w[i];
rep(1,k,i)b[i]=b[i-1]*3;
maxx1=b[k]-1;
rep(0,maxx1,i)
{
//0表示未知 1表示有毒 2表示无害.
int num=0;
rep(0,maxx,w1)//0表示无害 1表示有毒
{
int flag=0;
rep(1,k,w2)
{
if(i/b[w2-1]%3==0)continue;
if(i/b[w2-1]%3==1&&(w1>>w2-1&1))continue;
if(i/b[w2-1]%3==2&&!(w1>>w2-1&1))continue;
flag=1;
}
if(flag)continue;
num+=w[w1];
rep(1,k,j)
{
if(i/b[j-1]%3==1&&(w1>>j-1&1))continue;
if(i/b[j-1]%3==2&&!(w1>>j-1&1))continue;
if(i/b[j-1]%3==0)if(w1>>j-1&1)g[i][j]+=w[w1];
}
}
rep(1,k,j)
{
if(i/b[j-1]%3==1)g[i][j]=1;
if(i/b[j-1]%3==2)g[i][j]=0;
if(i/b[j-1]%3==0)g[i][j]/=num;
}
}
printf("%.3lf",dp(s1,s2,H,0,4));
return 0;
}
以上是关于P2489 [SDOI2011]迷宫探险 概率dp的主要内容,如果未能解决你的问题,请参考以下文章