Time:2016.08.24
Author:xiaoyimi
转载注明出处谢谢
传送门1
传送门2
思路:
毒瘤题目
考虑
f[i][x][y][h]
表示走到(x,y),血量为h时已知陷阱状态为i的最大概率
转移的话向(x+1,y)(x-1,y)(x,y+1)(x,y-1)走(以下为用x’,y’表示)
I.如果(x’,y’)是已知的陷阱
1.有害->
f[i][x′][y′][h−1]
2.无害->
f[i][x′][y′][h]
II是未知的陷阱,且陷阱种类为t
f[i′][x′][y′][h−1]∗g(i,t)+f[i′′][x′][y′][h]∗(1−g(i,t))
其中i’,i”分别表示知晓种类为t的陷阱后的新状态
g(i,t)表示陷阱状态为i时t种类陷阱的有害概率是多少
这样的话就比较清晰了
陷阱状态i可以用三进制数来表示——无害0,有害1,未知2
然后就是预处理g(i,t)
显然t在状态i中属于未知
这个可以暴力枚举状态i后处理其对每一种陷阱的影响
注意g(i,t)=P有害/(P有害+P无害)
思路还是比较好想的
但是真难调!
昨天晚上一直没调出来
原因
1.状态处理不当
把A当二(三)进制从小到大的第1位,B当第2位……
但是爆搜的时候给搞反了40->80
2.位运算自信不加括号,&优先级竟然比!=低,woc!80->90
3.换一个枚举顺序就可以90->100???
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#define in(x,y,z) (x<=y&&y<=z)
using namespace std;
int n,m,k,h;
char s[33][33];
int p[33],a[6];
double g[250][6],f[250][33][33][6],tmp[2];
bool vis[250][33][33][6];
int dx[]={1,0,-1,0},dy[]={0,-1,0,1};
int change(int now,int pos,int val)
{
for (int i=0;i<pos;++i)
a[i]=now%3,now/=3;
now+=val-2;
for (int i=pos-1;i>=0;--i)
now=now*3+a[i];
return now;
}
void dfs(int wei)
{
if (wei==k)
{
int now=0;
for (int i=k-1;i>=0;--i) now=now*3+a[i];
for (int i=0;i<k;++i)
if (a[i]==2)
{
tmp[0]=tmp[1]=0;
for (int j=0;j<(1<<k);++j)
{
bool flag=0;
for (int l=0;l<k;++l)
if (a[l]==2) continue;
else if (((j>>l)&1)!=a[l])
{
flag=1;
break;
}
if (flag) continue;
tmp[((j>>i)&1)]+=p[j];
}
g[now][i]=tmp[1]/(tmp[1]+tmp[0]);
}
return;
}
a[wei]=0;
dfs(wei+1);
a[wei]=1;
dfs(wei+1);
a[wei]=2;
dfs(wei+1);
}
double DP(int now,int x,int y,int h)
{
if (!h) return 0;
if (s[x][y]=='@') return 1;
if (vis[now][x][y][h]) return f[now][x][y][h];
vis[now][x][y][h]=1;
for (int i=0;i<4;++i)
if (in(1,dx[i]+x,n)&&in(1,dy[i]+y,m))
{
char ch=s[dx[i]+x][dy[i]+y];
if (ch=='#') continue;
else if (ch=='.'||ch=='@'||ch=='$') f[now][x][y][h]=max(f[now][x][y][h],DP(now,x+dx[i],y+dy[i],h));
else if (ch>='A'&&ch<='Z')
{
int t=ch-'A',p=now;
for (int j=0;j<t;++j) p/=3;
if (p%3==0)
f[now][x][y][h]=max(f[now][x][y][h],DP(now,x+dx[i],y+dy[i],h));
else if (p%3==1)
f[now][x][y][h]=max(f[now][x][y][h],DP(now,x+dx[i],y+dy[i],h-1));
else
f[now][x][y][h]=max(f[now][x][y][h],DP(change(now,t,0),x+dx[i],y+dy[i],h)*(1-g[now][t])
+DP(change(now,t,1),x+dx[i],y+dy[i],h-1)*g[now][t]);
}
}
return f[now][x][y][h];
}
main()
{
scanf("%d%d%d%d",&n,&m,&k,&h);
for (int i=1;i<=n;++i)
scanf("%s",s[i]+1);
for (int i=0;i<(1<<k);++i)
scanf("%d",p+i);
int x,y;
for (int i=1;i<=n;++i)
for (int j=1;j<=m;++j)
if (s[i][j]=='$')
{
x=i;y=j;break;
}
int tot=1;
for (int i=1;i<=k;++i) tot*=3;
--tot;
dfs(0);
printf("%.3lf\n",DP(tot,x,y,h));
}