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;
}

最新文章

  1. Java 网络爬虫获取页面源代码
  2. 如何在windows下的Python开发工具IDLE里安装其他模块?
  3. WPF,Silverlight与XAML读书笔记第四十六 - 外观效果之三皮肤与主题
  4. [logstash-input-redis]插件使用详解
  5. HDU #2966 In case of failure
  6. php编译报错 configure: error: Please reinstall the BZip2 distribution
  7. web app
  8. UIDatePicker swift
  9. ZOJ题目分类
  10. solr + tomcat 搭建
  11. ossim
  12. 用链表实现栈----《数据结构与算法分析----C语言描述》
  13. HDU 3836 Equivalent SetsTarjan+缩点)
  14. foreach 跟volist 有什么区别?
  15. UVALive 2035 The Monocycle(BFS状态处理+优先队列)
  16. jvm调优参数
  17. 二次剩余从csdn
  18. 第一类对象-&gt; 函数名 -&gt; 变量名
  19. PAT 1046 Shortest Distance[环形][比较]
  20. Java 方法重载与方法重写

热门文章

  1. 如何针对 iPhone X 设计网站?
  2. YAML &amp; JSON &amp;XML如何选择
  3. GitHub 热点速览 Vol.27:程序员的自我救赎——GitHub 摸鱼
  4. 简单的MVC框架
  5. [设计模式]工厂方法模式(Factory Method)
  6. git解决本地建立git仓库 连接远程git仓库出现拒绝合并问题
  7. 从连接器组件看Tomcat的线程模型——连接器简介
  8. http连接池存在的问题
  9. scratch编程——画笔模块画各种同心图案
  10. p46_IPv4地址