【Luogu】P2489迷宫探险(概率DP)
设f[i][j][k][l]是当前在(i,j),对陷阱的了解状态为k(0表示了解该陷阱为无危险,1表示了解该陷阱有危险,2不了解),l表示当前血,走出迷宫的概率
dfsDP即可。 注意随时更新和细节。
#include<cstdio> #include<cstdlib> #include<cctype> #include<algorithm> #include<cstring> #include<cmath> #define maxn 200 using namespace std; inline long long read(){ long long num=0,f=1; char ch=getchar(); while(!isdigit(ch)){ if(ch=='-') f=-1; ch=getchar(); } while(isdigit(ch)){ num=num*10+ch-'0'; ch=getchar(); } return num*f; } int u[5]={0,1,0,-1,0}; int w[5]={0,0,-1,0,1}; char mp[maxn][maxn]; double p[maxn]; double g[maxn*10][maxn]; int pw[maxn]; int n,m,e,h; int getlens(int x,int len){ return x/pw[len-1]%3; } double f[50][50][maxn*10][10]; bool vis[50][50][maxn*10][10]; int chan(int x,int len,int nu){ return x-getlens(x,len)*pw[len-1]+nu*pw[len-1]; } void dfs(int x,int y,int state,int blo){ //printf("%d %d\n",x,y); //printf("%d %d %d %d %.3lf\n",x,y,state,blo,f[x][y][state][blo]); if(vis[x][y][state][blo]) return; if(mp[x][y]=='@'){ f[x][y][state][blo]=1; vis[x][y][state][blo]=1; return; } if(blo==0){ f[x][y][state][blo]=0; vis[x][y][state][blo]=1; return; } vis[x][y][state][blo]=1; double &ans=f[x][y][state][blo]; for(int i=1;i<5;++i){ int nx=x+u[i],ny=y+w[i]; if(nx<1||nx>n||ny<1||ny>m||mp[nx][ny]=='#') continue; char c=mp[nx][ny]; int now=c-'A'+1; if(c=='.'||c=='$'||c=='@'||(now>=1&&now<=e&&getlens(state,now)==0)){ dfs(nx,ny,state,blo); ans=max(ans,f[nx][ny][state][blo]); } //if(now<1||now>e) continue; if(now>=1&&now<=e&&getlens(state,now)==1){ dfs(nx,ny,state,blo-1); ans=max(ans,f[nx][ny][state][blo-1]); } if(now>=1&&now<=e&&getlens(state,now)==2){ int sta=chan(state,now,1); int stb=chan(state,now,0); dfs(nx,ny,sta,blo-1); dfs(nx,ny,stb,blo); ans=max(ans,g[state][now]*f[nx][ny][sta][blo-1]+(1.0-g[state][now])*f[nx][ny][stb][blo]); } } f[x][y][state][blo]=ans; return; } int main(){ int sx,sy; n=read(),m=read(),e=read(),h=read(); for(int i=1;i<=n;++i){ scanf("%s",mp[i]+1); for(int j=1;j<=m;++j) if(mp[i][j]=='$'){ sx=i; sy=j; } } for(int i=0;i<(1<<e);++i) p[i]=read(); int Max=0;pw[0]=1; for(int i=1;i<=e;++i) pw[i]=pw[i-1]*3; //printf("%d",Max); for(int i=0;i<=pw[e];++i){ int sum=0; for(int j=0;j<(1<<e);++j){ bool flag=0; for(int k=1;k<=e;++k){ int now=getlens(i,k),ret=(j>>k-1)&1; if(now==2) continue; if(now!=ret){ flag=1; break; } } if(flag) continue; sum+=p[j]; for(int k=1;k<=e;++k){ if(getlens(i,k)!=2||((j>>k-1)&1)==0) continue; g[i][k]+=p[j]; } } for(int j=1;j<=e;++j) g[i][j]/=sum; } dfs(sx,sy,pw[e]-1,h); printf("%.3lf",f[sx][sy][pw[e]-1][h]); return 0; }