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;
    }
    
  • 相关阅读:
    Jenkins分享
    Java静态绑定和动态绑定
    SpringBoot中RedisTemplate订阅发布对象
    Idea项目:Failed to create a Maven project ‘…pom.xml’ already exists in VFS 解决
    Java Web不能不懂的知识
    Required String parameter 'id' is not present
    Hive使用druid做连接池代码实现
    Docker Toolbox常见错误解决方案
    初学者手册-MyBatis踩坑记(org.apache.ibatis.binding.BindingException)
    SpringMVC日志管理(自定义异常及自定义注解)
  • 原文地址:https://www.cnblogs.com/cjyyb/p/9906442.html
Copyright © 2011-2022 走看看