题目大意:太长了,略

bzoj luogu

并没有想到三进制状压

题解:

3进制状压陷阱的状态,0表示这种陷阱的状态未知,1已知危险,2已知不危险

然后预处理出在当前状态下,每种陷阱有害的概率,设为$g[s][i]$

已知是危险的,有害概率为1

已知是不危险的,有害概率为0

未知的部分用概率表格里符合当前状态的部分,才是正确的(比如第4个样例输出了0.857就是没用这种方法去求概率)

定义$f[x][y][s][h]$表示当前在(x,y),陷阱的状态为s,当前血量是h

然后记忆化爆搜即可

...

此题解针对在luogu上交了,WA了第2个/第8个/第10个点,然后“换了个枚举顺序”就恰好A掉了这道题的情况

仔细观察发现上面那种做法貌似是有一些问题的

比如从上一层xxxx往下走↓,走到了yyyy这个状态,然后,yyyy还会往上跑从xxxx更新,得到了一个#$%@的“最优解”,这可能是yyyy往上跑的最优解,但也可能不是!

因为你状态xxxx可能还有某个方向没有遍历,但我们草率得把f[xxxx]这个“并不最优解”去更新f[yyyy]

那如果在另一次搜索中,由某个状态zzzz往上走↑,又跑到了yyyy,由于访问过了yyyy,所以返回了f[yyyy],然而这个f[yyyy]可能并不是最优解,导致答案出错!

为了避免这种错误,我们额外记录一维,表示从那个方向跑到当前状态,$f[x][y][s][h][t]$,t表示上一层是从哪个方向来的即可,虽然牺牲了一些常数但保证了答案的正确性!

 #include <cstdio>
#include <cstring>
#include <algorithm>
#define N 35
#define M 250
#define dd double
#define idx(x) (x-'A'+1)
using namespace std; int n,m,sx,sy,K,H;
char str[N][N];
int xx[]={-,,,},yy[]={,,,-};
int pw[]={,,,,,,};
int mp[N][N],pro[M];
dd f[N][N][M][][5],g[M][],dan[];
bool vis[N][N][M][][];
bool check(int x,int y){
if(x<||x>n||y<||y>m||mp[x][y]==-) return ;
else return ;}
int p[M][];
dd dfs(int x,int y,int s,int h,int fa)
{
if(h<=) return ;
if(vis[x][y][s][h][fa]) return f[x][y][s][h][fa];
vis[x][y][s][h][fa]=;
if(mp[x][y]==K+){
f[x][y][s][h][fa]=;
return ;
}int tx,ty,t1,t2,pt;
dd tmp=;
for(int i=;i<;i++)
{
tx=x+xx[i],ty=y+yy[i];
if(!check(tx,ty)) continue;
pt=mp[tx][ty],t1=t2=s;
dd ans1=,ans2=;
if(pt>&&pt<=K&&!p[s][pt]) t1+=(*pw[pt-]);
if(pt>&&pt<=K&&!p[s][pt]) t2+=(*pw[pt-]);
if(pt!=-){
if(g[s][pt]>0.0&&h>) ans1=dfs(tx,ty,t1,h-,(i+)%);
if(g[s][pt]<1.0)ans2=dfs(tx,ty,t2,h,(i+)%);
tmp=max(tmp,1.0*g[s][pt]*ans1+(1.0-g[s][pt])*ans2);
}
}f[x][y][s][h][fa]=tmp;
return f[x][y][s][h][fa];
}
void Pre()
{
for(int i=;i<(<<K);i++)
scanf("%d",&pro[i]);
for(int i=;i<pw[K];i++){
int x=i,k=K;
while(k){
p[i][k]=x/pw[k-];
x%=pw[k-],k--;}
}
for(int i=;i<pw[K];i++)
{
int tot=,sum;
for(int j=;j<K;j++)
dan[j+]=;
for(int s=;s<(<<K);s++){
int fl=;
for(int j=;j<K;j++)
if((s&(<<j))&&p[i][j+]==) {fl=;break;}
else if((!(s&(<<j)))&&p[i][j+]==) {fl=;break;}
if(!fl) continue;
tot+=pro[s];
}int x=i,k=K;
for(int k=;k<=K;k++)
{
if(p[i][k]==){
sum=;
for(int s=;s<(<<K);s++)
{
int fl=;
for(int j=;j<K;j++)
if((s&(<<j))&&p[i][j+]==) {fl=;break;}
else if((!(s&(<<j)))&&p[i][j+]==) {fl=;break;}
if(!fl) continue;
if(s&(<<(k-))) sum+=pro[s];
}g[i][k]=1.0*sum/tot;
}
if(p[i][k]==){g[i][k]=1.0;}
if(p[i][k]==){g[i][k]=0.0;}
}
}
}
int main()
{
scanf("%d%d%d%d",&n,&m,&K,&H);
for(int i=;i<=n;i++){
scanf("%s",str[i]+);
for(int j=;j<=m;j++)
if(str[i][j]=='$') sx=i,sy=j;
else if(str[i][j]=='@') mp[i][j]=K+;
else if(str[i][j]=='#') mp[i][j]=-;
else if(str[i][j]=='.') mp[i][j]=;
else mp[i][j]=idx(str[i][j]);
}
Pre();
printf("%.3lf\n",dfs(sx,sy,,H,));
return ;
}

BZOJ 2246 [SDOI2011]迷宫探险 (记忆化搜索)的更多相关文章

  1. BZOJ 2246 [SDOI2011]迷宫探险 ——动态规划

    概率DP 记忆化搜索即可,垃圾数据,就是过不掉最后一组 只好打表 #include <cstdio> #include <cstring> #include <iostr ...

  2. BZOJ.2246.[SDOI2011]迷宫探险(DP 记忆化搜索 概率)

    题目链接 求最大的存活概率,DP+记忆化. 用f[s][x][y][hp]表示在s状态,(x,y)点,血量为hp时的存活概率. s是个三进制数,记录每个陷阱无害/有害/未知. 转移时比较容易,主要是在 ...

  3. [BZOJ 1068] [SCOI2007] 压缩 【记忆化搜索】

    题目链接:BZOJ - 1068 题目分析 这种记忆化搜索(区间 DP) 之前就做过类似的,也是字符串压缩问题,不过这道题稍微复杂一些. 需要注意如果某一段是 S1S1 重复,那么可以变成 M + S ...

  4. BZOJ 1079: [SCOI2008]着色方案 记忆化搜索

    1079: [SCOI2008]着色方案 Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://www.lydsy.com/JudgeOnline/p ...

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

    [BZOJ2246][SDOI2011]迷宫探险(搜索,动态规划) 题面 BZOJ 洛谷 题解 乍一看似乎是可以求出每个东西是陷阱的概率,然而会发现前面走过的陷阱是不是陷阱实际上是会对当前状态产生影响 ...

  6. [BZOJ 1048] [HAOI2007] 分割矩阵 【记忆化搜索】

    题目链接:BZOJ - 1048 题目分析 感觉这种分割矩阵之类的题目很多都是这样子的. 方差中用到的平均数是可以直接算出来的,然后记忆化搜索 Solve(x, xx, y, yy, k) 表示横坐标 ...

  7. [BZOJ 1055] [HAOI2008] 玩具取名 【记忆化搜索】

    题目链接:BZOJ - 1055 题目分析 这种类似区间 DP 的记忆化搜索都是很相近的,比如字符串压缩和字符串扩展都差不多. 都是将现在 Solve 的区间分成子区间,再求解子区间. 这道题 Sol ...

  8. [Swust OJ 409]--小鼠迷宫问题(BFS+记忆化搜索)

    题目链接:http://acm.swust.edu.cn/problem/409/ Time limit(ms): 1000 Memory limit(kb): 65535   Description ...

  9. BZOJ 3895 3895: 取石子 / Luogu SP9934 ALICE - Alice and Bob (博弈 记忆化搜索)

    转自PoPoQQQ大佬博客 题目大意:给定n堆石子,两人轮流操作,每个人可以合并两堆石子或拿走一个石子,不能操作者输,问是否先手必胜 直接想很难搞,我们不妨来考虑一个特殊情况 假设每堆石子的数量都&g ...

随机推荐

  1. table标签 在谷歌和ie浏览器下不同的表现效果

    在项目中有了一个这样的需求: 我需要利用vue的模板语法v-for循环生成tr,这个tr是需要双重循环来确定其个数的, 我的实现: 我在tr外面包了一个template标签, 效果: 谷歌浏览器下实现 ...

  2. 字符串时间转Date格式

    /** * 字符串时间格式转 Date 格式 * @param strDate * @return */ public static Date getDateTimeByStringTime(Stri ...

  3. Linux学习01

    Linux学习第一天 1.使用VM安装RHEL7.0 具体参见刘遄老师的<Linux就该怎么学>https://www.linuxprobe.com/chapter-01.html 2.R ...

  4. Laravel源码解析之从入口开始

    前言 提升能力的方法并非使用更多工具,而是解刨自己所使用的工具.今天我们从Laravel启动的第一步开始讲起. 入口文件 laravel是单入口框架,所有请求必将经过index.php define( ...

  5. JavaScript 常见创建对象的方式

    JavaScript 有哪几种创建对象的方式? javascript创建对象简单的说,无非就是使用内置对象或各种自定义对象,当然还可以用JSON:但写法有很多种,也能混合使用. (1)对象字面量的方式 ...

  6. CSS隐藏overflow默认滚动条同时保留滚动效果

    主要应用于移动端场景,仿移动端滚动效果.对于隐藏滚动条,众所周知overflow:hidden,但是想要的滚动效果也没了. 所以对于移动端webkit内核提供一个伪类选择器: .element::-w ...

  7. JS 一个简单的隔行变色函数

    //输入要隔行变色的标签名 function setbgColor(tr){ var tr = document.getElementsByTagName("tr"); for(v ...

  8. HH实习(hpu1287)(斐波那契运用)

    HH实习 Time Limit: 1 Sec  Memory Limit: 128 MB Submit: 44  Solved: 29 [Submit][id=1287">Status ...

  9. [Python]threading local 线程局部变量小測试

    概念 有个概念叫做线程局部变量.一般我们对多线程中的全局变量都会加锁处理,这样的变量是共享变量,每一个线程都能够读写变量,为了保持同步我们会做枷锁处理.可是有些变量初始化以后.我们仅仅想让他们在每一个 ...

  10. uva 10641 (来当雷锋的这回....)

    #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> using ...