码迷,mamicode.com
首页 > 其他好文 > 详细

P2489 [SDOI2011]迷宫探险 概率dp

时间:2020-06-09 14:55:39      阅读:65      评论:0      收藏:0      [点我收藏+]

标签:max   open   char   www   一个   概率dp   坑点   freopen   搜索   

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

标签:max   open   char   www   一个   概率dp   坑点   freopen   搜索   

原文地址:https://www.cnblogs.com/chdy/p/13072092.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!