zoukankan      html  css  js  c++  java
  • 【BZOJ2246】[SDOI2011]迷宫探险(搜索,动态规划)

    【BZOJ2246】[SDOI2011]迷宫探险(搜索,动态规划)

    题面

    BZOJ
    洛谷

    题解

    乍一看似乎是可以求出每个东西是陷阱的概率,然而会发现前面走过的陷阱是不是陷阱实际上是会对当前状态产生影响的。考虑一下状压,因为出了是陷阱和不是陷阱,还有一种情况是未知。所以三进制状压。
    (0)表示是有害陷阱,(1)表示不是,(2)表示未知。
    那么假如我们知道了一个当前的三进制状态,如何确定当前的某个未知的陷阱是否有害的概率呢?
    这个显然可以暴力提前预处理出来。
    那么这就很好办了,设(f[x][y][hp][S])表示当前在((x,y))位置,剩余血量为(hp),当前陷阱的状态集合为(S)的最大概率。那么直接记忆化爆搜就可以知道结果了。
    然而我觉得这个做法是假的,因为你转移的时候可能成环,这也就解释了为什么不按照题解的方向就过不了,然而不这么做还能怎么做啊QwQ。

    似乎BZOJ上的数据有锅,怎么交都是T,我蒯别的题解也T了。。。。
    然后我改成scanf就WA了,应该数据锅了,到洛谷交吧。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    #define cmax(a,b) (a=((a)<(b)?(b):(a)))
    int bin[]={1,3,9,27,81,243,729,2187,6561};
    int let(int x,int k){return x/=bin[k];}
    int rit(int x,int k){return x*=bin[k];}
    int get(int x,int k){x/=bin[k];return x%3;}
    double f[35][35][729][10];
    bool vis[35][35][729][10];
    int n,m,K,H,P[50];
    char g[35][35];
    double p[729][10];
    int bx,by,ex,ey;
    int d[4][2]={1,0,0,-1,-1,0,0,1};
    double dfs(int x,int y,int S,int hp)
    {
    	if(vis[x][y][S][hp])return f[x][y][S][hp];
    	if(!hp)return f[x][y][S][hp]=0;
    	if(g[x][y]=='@')return f[x][y][S][hp]=1;
    	vis[x][y][S][hp]=true;
    	for(int i=0;i<4;++i)
    	{
    		int xx=x+d[i][0],yy=y+d[i][1];
    		if(xx<1||yy<1||xx>n||yy>m)continue;
    		if(g[xx][yy]=='#')continue;
    		if(g[xx][yy]>='A'&&g[xx][yy]<='Z')
    		{
    			int k=g[xx][yy]-65;
    			if(get(S,k)<2)//Know
    				cmax(f[x][y][S][hp],dfs(xx,yy,S,hp-get(S,k)));
    			else//Unknow
    				cmax(f[x][y][S][hp],dfs(xx,yy,S-bin[k],hp-1)*p[S][k]+dfs(xx,yy,S-bin[k]*2,hp)*(1-p[S][k]));
    		}
    		else
    			cmax(f[x][y][S][hp],dfs(xx,yy,S,hp));
    	}
    	return f[x][y][S][hp];
    }
    int main()
    {
    	scanf("%d%d%d%d",&n,&m,&K,&H);
    	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]=='$')bx=i,by=j;
    			else if(g[i][j]=='@')ex=i,ey=j;
    	if(!ex){puts("0.000");return 0;}
    	for(int S=0;S<bin[K];++S)
    	{
    		int sumP=0;
    		for(int i=0;i<1<<K;++i)
    		{
    			bool fl=true;
    			for(int j=0;j<K;++j)
    			{
    				int x=get(S,j);if(x==2)continue;
    				if(((i>>j)&1)!=x){fl=false;break;}
    			}
    			if(!fl)continue;
    			sumP+=P[i];
    			for(int j=0;j<K;++j)
    				if(get(S,j)==2&&(i&(1<<j)))p[S][j]+=P[i];
    		}
    		for(int j=0;j<K;++j)p[S][j]/=sumP;
    	}
    	printf("%.3lf
    ",dfs(bx,by,bin[K]-1,H));
    	return 0;
    }
    
  • 相关阅读:
    设计模式整理_单例设计模式
    设计模式整理_工厂模式
    设计模式整理_装饰者模式
    设计模式整理_观察者模式
    设计模式整理_策略模式
    JavaSE复习_7 异常
    JavaSE复习_6 枚举类
    JavaSE复习_5 Eclipse的常见操作
    pta编程题19 Saving James Bond 2
    ImportError: No module named PIL
  • 原文地址:https://www.cnblogs.com/cjyyb/p/9906442.html
Copyright © 2011-2022 走看看