zoukankan      html  css  js  c++  java
  • [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
    ",DP(tot,sx,sy,h));
    	return 0;
    }
    
  • 相关阅读:
    c文件操作库
    双链常用操作2
    双向链表常用操作
    c队列操作
    c日期格式化操作之date
    单链常用操作类
    c字符串常用操作
    双向链表通用类
    c栈操作
    poj2509
  • 原文地址:https://www.cnblogs.com/void-f/p/8715813.html
Copyright © 2011-2022 走看看