LINK:迷宫探险

题目中要求在最优的策略下的最大概率 而并非期望概率。

一个坑点 题目中虽然没有明说 但是 探险者是知道地图的模样和每个陷阱的概率的。

所以才有最优策略一说。

最优策略尽管不知道可以随便走取max即可。

容易想到 对于当前状态 有 x,y,hp,s 来描述 。倒着设状态 那就是当前状态能到达终点的最大概率。

定义hp s都是递增的 不过还是不能线性递推。存在问题 可能状态之间可以互相转移的问题。

显然状态转移回来是不必要的 所以此时概率为0 利用dfs栈可以很容易判断出来 所以考虑记忆化搜索。

不过这引出了另外一个问题 当前状态可能被多次访问到 不过当前状态被第一次访问到已经被标记了 此时可能不是最优的。

容易想到转移到当前状态最多只有4种可能都记录下来即可。

6.16 Update:被wn给hack掉了 发现上面的思路在能走回路的时候会挂掉。

原因:存在一种最优方案使得从某个点走到另外一个点然后再跑回来的情况。

同时也存在一开始就跑过去的情况是最优的。

实际上上述做法能解决第一种情况 而第二种情况就在第一种情况被解决时 被卡掉了。

因为 可以走完这步 发现无毒 然后一些较优的状态可能被一些情况给卡掉了 因为原地乱转的原因。

一个好的解决方法:强制不让其乱转 保证状态之间的拓扑关系 这样就不会出现问题了。

//#include<bits\stdc++.h>
#include<iostream>
#include<iomanip>
#include<cstdio>
#include<cstring>
#include<string>
#include<ctime>
#include<cmath>
#include<cctype>
#include<cstdlib>
#include<queue>
#include<deque>
#include<stack>
#include<vector>
#include<algorithm>
#include<utility>
#include<bitset>
#include<set>
#include<map>
#define ll long long
#define db double
#define INF 1000000000000000000ll
#define ldb long double
#define pb push_back
#define put_(x) printf("%d ",x);
#define get(x) x=read()
#define gt(x) scanf("%d",&x)
#define gi(x) scanf("%lf",&x)
#define put(x) printf("%d\n",x)
#define putl(x) printf("%lld\n",x)
#define gc(a) scanf("%s",a+1)
#define rep(p,n,i) for(RE int i=p;i<=n;++i)
#define go(x) for(int i=lin[x],tn=ver[i];i;tn=ver[i=nex[i]])
#define fep(n,p,i) for(RE int i=n;i>=p;--i)
#define vep(p,n,i) for(RE int i=p;i<n;++i)
#define pii pair<int,int>
#define mk make_pair
#define RE register
#define P 1000000007
#define gf(x) scanf("%lf",&x)
#define pf(x) ((x)*(x))
#define uint unsigned long long
#define ui unsigned
#define EPS 1e-8
#define sq sqrt
#define mod 998244353
#define S second
#define F first
#define Set(a,v) memset(a,v,sizeof(a))
using namespace std;
char buf[1<<15],*fs,*ft;
inline char getc()
{
return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;
}
inline int read()
{
RE int x=0,f=1;RE char ch=getc();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getc();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getc();}
return x*f;
}
//偷税吧 少年
const int MAXN=33,N=244;
int n,m,H,k,maxx,s1,s2,maxx1,ans;
int w[1<<5],b[N],id;
int vis[MAXN][MAXN][6][N];
db g[N][6],f[MAXN][MAXN][6][N];
char a[MAXN][MAXN];
int dx[4]={1,-1,0,0};
int dy[4]={0,0,-1,1};
vector<pii>v[MAXN][MAXN][MAXN];
int mark[MAXN][MAXN],cc[N];
inline int pd(int s,int x)
{
return s>>x-1&1;
}
inline void dfs(int x,int y,int s,int xx,int yy)
{
if(mark[x][y]==id)return;
mark[x][y]=id;
if(a[x][y]=='@'||(a[x][y]>='A'&&a[x][y]<='Z'&&!pd(s,a[x][y]-'A'+1)&&(x!=xx||y!=yy)))
{
v[s][xx][yy].pb(mk(x,y));return;
}
for(int i=0;i<4;++i)
{
int wx=dx[i]+x;
int wy=dy[i]+y;
if(wx<=0||wx>n||wy<=0||wy>m)continue;
if(a[wx][wy]=='#')continue;
dfs(wx,wy,s,xx,yy);
}
}
inline void prepare()
{
rep(1,n,i)rep(1,m,j)
{
if(a[i][j]=='#'||a[i][j]=='@')continue;
rep(0,maxx,s)
{
++id;
dfs(i,j,s,i,j);
}
}
}
inline db dp(int x,int y,int hp,int s)
{
if(vis[x][y][hp][s])return f[x][y][hp][s];
vis[x][y][hp][s]=1;
if(hp==0)return f[x][y][hp][s]=0;
if(a[x][y]=='@')return f[x][y][hp][s]=1;
db ans=0;int ww=cc[s];
vep(0,v[ww][x][y].size(),i)
{
int xx=v[ww][x][y][i].F;
int yy=v[ww][x][y][i].S;
if(a[xx][yy]=='@')ans=max(ans,dp(xx,yy,hp,s));
else
{
int ss=a[xx][yy]-'A'+1;
if(s/b[ss-1]%3==1)ans=max(ans,dp(xx,yy,hp-1,s));
if(s/b[ss-1]%3==0)
ans=max(ans,dp(xx,yy,hp-1,s+b[ss-1])*g[s][ss]
+dp(xx,yy,hp,s+b[ss-1]*2)*(1-g[s][ss]));
}
}
return f[x][y][hp][s]=ans;
}
int main()
{
//freopen("1.in","r",stdin);
gt(n);gt(m);gt(k);gt(H);
rep(1,n,i)
{
gc(a[i]);
rep(1,m,j)if(a[i][j]=='$')s1=i,s2=j;
}
maxx=1<<k;--maxx;b[0]=1;
rep(0,maxx,i)get(w[i]),ans+=w[i];
rep(1,k,i)b[i]=b[i-1]*3;
maxx1=b[k]-1;
rep(0,maxx1,i)
{
//0表示未知 1表示有毒 2表示无害.
int num=0;
rep(0,maxx,w1)//0表示无害 1表示有毒
{
int flag=0;
rep(1,k,w2)
{
if(i/b[w2-1]%3==0)continue;
if(i/b[w2-1]%3==1&&(w1>>w2-1&1))continue;
if(i/b[w2-1]%3==2&&!(w1>>w2-1&1))continue;
flag=1;
}
if(flag)continue;
num+=w[w1];
rep(1,k,j)
{
if(i/b[j-1]%3==1&&(w1>>j-1&1))continue;
if(i/b[j-1]%3==2&&!(w1>>j-1&1))continue;
if(i/b[j-1]%3==0)if(w1>>j-1&1)g[i][j]+=w[w1];
}
}
rep(1,k,j)
{
if(i/b[j-1]%3==1)g[i][j]=1;
if(i/b[j-1]%3==2)g[i][j]=0,cc[i]|=(1<<j-1);
if(i/b[j-1]%3==0)g[i][j]/=num;
}
}
prepare();
printf("%.3lf",dp(s1,s2,H,0));
return 0;
}

P2489 [SDOI2011]迷宫探险 概率dp的更多相关文章

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

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

  2. BZOJ2246 [SDOI2011]迷宫探险 【记忆化搜索dp + 概率】

    题目 输入格式 输出格式 仅包含一个数字,表示在执行最优策略时,人物活着走出迷宫的概率.四舍五入保留3位小数. 输入样例 4 3 3 2 .$. A#B A#C @@@ 143 37 335 85 9 ...

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

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

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

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

  5. BZOJ2707 [SDOI2012]走迷宫 【概率dp + tarjan + 高斯消元】

    题目 Morenan被困在了一个迷宫里.迷宫可以视为N个点M条边的有向图,其中Morenan处于起点S,迷宫的终点设为T.可惜的是,Morenan非常的脑小,他只会从一个点出发随机沿着一条从该点出发的 ...

  6. BZOJ 2246 [SDOI2011]迷宫探险 (记忆化搜索)

    题目大意:太长了,略 bzoj luogu 并没有想到三进制状压 题解: 3进制状压陷阱的状态,0表示这种陷阱的状态未知,1已知危险,2已知不危险 然后预处理出在当前状态下,每种陷阱有害的概率,设为$ ...

  7. 【Luogu】P2489迷宫探险(概率DP)

    题目链接 设f[i][j][k][l]是当前在(i,j),对陷阱的了解状态为k(0表示了解该陷阱为无危险,1表示了解该陷阱有危险,2不了解),l表示当前血,走出迷宫的概率 dfsDP即可. 注意随时更 ...

  8. hdu 4035 2011成都赛区网络赛E 概率dp ****

    太吊了,反正我不会 /* HDU 4035 dp求期望的题. 题意: 有n个房间,由n-1条隧道连通起来,实际上就形成了一棵树, 从结点1出发,开始走,在每个结点i都有3种可能: 1.被杀死,回到结点 ...

  9. [转]概率DP总结 by kuangbin

    概率类题目一直比较弱,准备把kuangbin大师傅总结的这篇题刷一下! 我把下面的代码换成了自己的代码! 原文地址:http://www.cnblogs.com/kuangbin/archive/20 ...

随机推荐

  1. 转载之html特殊字符的html,js,css写法汇总

    箭头类 符号 UNICODE 符号 UNICODE HTML JS CSS HTML JS CSS ⇠ &#8672 \u21E0 \21E0 ⇢ &#8674 \u21E2 \21E ...

  2. 【Flutter 实战】动画核心

    老孟导读:动画系统是任何一个UI框架的核心功能,也是开发者学习一个UI框架的重中之重,同时也是比较难掌握的一部分,下面我们就一层一层的揭开 Flutter 动画的面纱. 任何程序的动画原理都是一样的, ...

  3. Zip破解工具Fcrackzip使用简介

    0x00 fcrackzip简单介绍 fcrackzip是一款专门破解zip类型压缩文件密码的工具,工具小巧方便.破解速度快,能使用字典和指定字符集破解,适用于linux.mac osx 系统 0x0 ...

  4. day16 三层装饰器和迭代器

    一. 经典的两层装饰器,也是标准装饰器 案例 import time def outter1(func): def wrapper(*args, **kwargs): start = time.tim ...

  5. day18 作业

    目录 1.编写课上讲解的有参装饰器准备明天默写 2.在文件开头声明一个空字典,然后在每个函数前加上装饰器,完成自动添加到字典的操作 3.编写日志装饰器,实现功能如:一旦函数f1执行,则将消息2017- ...

  6. es6新增特性总结

    定义 ES6是ECMA为JavaScript制定的第6个标准版本,标准委员会决定,标准在每年6月正式发布并作为当年的正式版本,接下来的时间里就在此版本的基础上进行改动,直到下一年6月草案就自然变成新一 ...

  7. 如何实现 token 加密

    jwt举例 需要一个secret(随机数) 后端利用secret和加密算法(如:HMAC-SHA256)对payload(如账号密码)生成一个字符串(token),返回前端 前端每次request在h ...

  8. SpringBoot2 整合JTA组件,多数据源事务管理

    本文源码:GitHub·点这里 || GitEE·点这里 一.JTA组件简介 1.JTA基本概念 JTA即Java-Transaction-API,JTA允许应用程序执行分布式事务处理,即在两个或多个 ...

  9. Elasticsearch从入门到放弃:再聊搜索

    在前文中我们曾经聊过搜索文档的方法,Elasticsearch 一般适用于读多写少的场景,因此我们需要更多的关注读操作. Elasticsearch 提供的 Search API 可以分为 URI S ...

  10. T133316 57级返校测试重测-T4-字符串的修改

    大致题意: 有一个A字符串和一个B字符串, 操作将A或A的一个后缀修改为B, 求最少的操作数. 有三个操作为: 删除: 删除掉 A 中的某一个字符. 添加: 将某一个字符添加到 A 中任意位置. 替换 ...