[Bzoj2246]迷宫探险(概率+DP)

Description

题目链接

Solution

用三进制表示陷阱状态,1表示有害,2表示无害,0表示不知道

\(f[S][i]\)表示状态为S时陷阱i有害的概率,这个可以预处理出

\(d[S][i][j][h]\)表示状态为S,在坐标\((i,j)\),血量为h时的答案

然后就可以DP了,记忆化搜索

Code

#include <cstdio>
#include <algorithm>
#define db double
#define Sta 300
#define N 36
using namespace std;

const int dx[]={0,0,1,-1};
const int dy[]={1,-1,0,0};
db dp[Sta][N][N][6],f[Sta][N];
int n,m,k,h,p[N],sx,sy,A[6]; 
char g[N][N];

inline int read(){
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}

db tmp[2];
void dfs(int x){
	if(x==k){
		int S=0;
		for(int i=k-1;i>=0;--i) S=S*3+A[i];
		for(int i=0;i<k;++i){
			if(A[i]!=2) continue;
			tmp[0]=tmp[1]=0;
			for(int j=0;j<(1<<k);++j){
				bool flag=0;
				for(int l=0;l<k;++l)
					if(A[l]==2) continue;
					else if(A[l]!=((j>>l)&1)){flag=1;break;}
				if(flag) continue;
				tmp[(j>>i)&1]+=p[j];
			}
			f[S][i]=tmp[1]/(tmp[1]+tmp[0]);
		}
	}else for(int i=0;i<=2;++i){A[x]=i;dfs(x+1);}
}

int Change(int S,int pos,int x){
	for(int i=0;i<pos;++i) A[i]=S%3,S/=3;S-=x;
	for(int i=pos-1;i>=0;--i) S=S*3+A[i];
	return S;
} 

db DP(int S,int x,int y,int h){
	if(!h) return 0;
	if(g[x][y]=='@') return 1;
	db &tmp=dp[S][x][y][h];
	if(tmp!=-1) return tmp;
	tmp=0;
	
	for(int d=0;d<4;++d){
		int nx=x+dx[d],ny=y+dy[d],tS=S;
		if(nx<=0||ny<=0||nx>n||ny>m) continue;
		char ch=g[nx][ny];
		if(ch=='#') continue;
		else if(ch=='.'||ch=='$'||ch=='@') tmp=max(tmp,DP(S,nx,ny,h));
		else if(ch>='A'&&ch<='Z'){
			int id=ch-'A';
			for(int i=0;i<id;++i) tS/=3;
			if(tS%3==2) tmp=max(tmp,DP(Change(S,id,2),nx,ny,h)*(1-f[S][id])+DP(Change(S,id,1),nx,ny,h-1)*f[S][id]); 
			else tmp=max(tmp,DP(S,nx,ny,h-(tS%3)));
		}
	}
	return tmp;
}

int main(){
	n=read(),m=read(),k=read(),h=read();
	for(int i=1;i<=n;++i) scanf("%s",g[i]+1);
	for(int i=0;i<(1<<k);++i) scanf("%d",&p[i]);
	for(int i=1;i<=n;++i)for(int j=1;j<=m;++j)if(g[i][j]=='$'){sx=i;sy=j;break;}
	int tot=1;for(int i=1;i<=k;++i)tot*=3;--tot;
	dfs(0);
	for(int i=0;i<Sta;++i)for(int j=1;j<N;++j)for(int k=1;k<N;++k)for(int l=0;l<6;++l)dp[i][j][k][l]=-1;
	printf("%.3lf\n",DP(tot,sx,sy,h));
	return 0;
}
posted @ 2018-04-04 10:22  void_f  阅读(231)  评论(0编辑  收藏  举报