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

题目

输入格式

输出格式

仅包含一个数字,表示在执行最优策略时,人物活着走出迷宫的概率。四舍五入保留3位小数。

输入样例

4 3 3 2

.$.

A#B

A#C

@@@

143 37 335 85 95 25 223 57

输出样例

0.858

提示

题解

毒瘤dp题

我们设\(f[x][y][s][h]\)表示从点\((x,y)\)出发,所有陷阱状态为\(s\),生命值为\(h\),存活的期望概率

我们枚举邻点,选择存活概率最大的作为当前\(f\)的值

除了墙,有以下情况:

①如果是空地或者终点,直接转移\(f[nx][ny][s][h]\)

②如果是陷阱:

1、如果陷阱已知

无害则同空地的转移

有害则转移的同时\(h - 1\)

2、如果陷阱位置

那么就是\(g[s][t] * f[nx][ny][s‘][h - 1] + (1 - g[s][t]) * f[nx][ny][s‘‘][h]\)

其中\(g[s][t]\)表示在已知状态为s的情况下,陷阱\(t\)有害的概率,可以预处理出来

\(s‘\)和\(s‘‘\)就是加入新状态的s

至于g数组的预处理,对于每种s,枚举未知位置的子集,将各种情况有害的加到对应陷阱去,然后除以总值

为什么换一个搜索顺序才能A???

#include<iostream>
#include<cstdio>
#include<cctype>
#include<cstring>
#include<algorithm>
#define REP(i,n) for (int i = 1; i <= (n); i++)
using namespace std;
inline int read(){
    int out = 0,flag = 1; char c = getchar();
    while (c < 48 || c > 57){if (c == ‘-‘) flag = -1; c = getchar();}
    while (c >= 48 && c <= 57){out = (out << 3) + (out << 1) + c - 48; c = getchar();}
    return out * flag;
}
double f[32][32][250][6],g[250][6],p[100];
int vis[32][32][250][6],bin[10];
int n,m,K,H,Sx,Sy,X[4] = {1,0,-1,0},Y[4] = {0,-1,0,1};
int G[32][32];
void init(){
    n = read(); m = read(); K = read(); H = read();
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= m; j++){
            char c = getchar();
            while (!isprint(c)) c = getchar();
            if (c == ‘.‘) G[i][j] = 0;
            else if (c == ‘#‘) G[i][j] = -1;
            else if (c == ‘$‘) G[i][j] = 0,Sx = i,Sy = j;
            else if (c == ‘@‘) G[i][j] = -2;
            else G[i][j] = c - ‘A‘ + 1;
        }
    //REP(i,n) {REP(j,m) printf("%d ",G[i][j]); puts("");}
    bin[0] = 1;
    for (int i = 1; i <= K; i++) bin[i] = bin[i - 1] * 3;
    //REP(i,K) printf("%d ",bin[i]); puts("");
    int maxv = (1 << K) - 1,maxp = bin[K] - 1;
    for (int s = 0; s <= maxv; s++) p[s] = read();
    for (int s = 0; s <= maxp; s++){
        int e = 0,t = 0; double sum = 0;
        for (int i = s,j = 1; j <= K; j++,i /= 3){
            if (i % 3 == 0) t |= (1 << j - 1);
            else if (i % 3 == 2) e |= (1 << j - 1);
        }
        for (int i = t; ; i = (i - 1) & t){
            int to = (e | i);
            sum += p[to];
            for (int j = 1; j <= K; j++)
                if (to & (1 << j - 1)) g[s][j] += p[to];
            if (!i) break;
        }
        for (int i = 1; i <= K; i++)
            g[s][i] /= sum;
    }
}
double F(int x,int y,int s,int h){
    if (vis[x][y][s][h]) return f[x][y][s][h];
    if (h == 0){
        vis[x][y][s][h] = 1;
        return f[x][y][s][h] = 0;
    }
    if (G[x][y] == -2){
        vis[x][y][s][h] = 1;
        return f[x][y][s][h] = 1;
    }
    vis[x][y][s][h] = 1;
    double& ff = f[x][y][s][h];
    ff = 0;
    int nx,ny;
    for (int k = 0; k < 4; k++){
        nx = x + X[k];
        ny = y + Y[k];
        if (nx < 1 || ny < 1 || nx > n || ny > m || G[nx][ny] == -1) continue;
        if (G[nx][ny] == 0 || G[nx][ny] == -2){
            ff = max(ff,F(nx,ny,s,h));
        }
        else {
            int t = G[nx][ny];
            if ((s / bin[t - 1]) % 3 == 1) ff = max(ff,F(nx,ny,s,h));
            else if ((s / bin[t - 1]) % 3 == 2) ff = max(ff,F(nx,ny,s,h - 1));
            else {
                ff = max(ff,g[s][t] * F(nx,ny,s + 2 * bin[t - 1],h - 1) + (1 - g[s][t]) * F(nx,ny,s + bin[t - 1],h));
            }
        }
    }
    return ff;
}
int main(){
    init();
    if (n == 0) return 0;
    else printf("%.3lf\n",F(Sx,Sy,0,H));
    return 0;
}

原文地址:https://www.cnblogs.com/Mychael/p/8585151.html

时间: 2024-11-11 01:39:21

BZOJ2246 [SDOI2011]迷宫探险 【记忆化搜索dp + 概率】的相关文章

hdu 4960 记忆化搜索 DP

Another OCD Patient Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others) Total Submission(s): 490    Accepted Submission(s): 180 Problem Description Xiaoji is an OCD (obsessive-compulsive disorder) patient. This morni

bzoj2246: [SDOI2011]迷宫探险

2246: [SDOI2011]迷宫探险 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 202  Solved: 118[Submit][Status][Discuss] Description 这是一个单人游戏. 游戏开始时,玩家控制的人物出生在迷宫的某个位置,玩家的目标是控制人物走到迷宫的某个出口(出口可能有多个).迷宫里有k类陷阱(用"A"."B"."C"--表示,相同字母代表相同类型的陷阱

HDU 1078 FatMouse and Cheese(记忆化搜索DP)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1078 题目大意:一个n*n的图,每个点都有奶酪,老鼠从(0,0)开始走,每次最多只能走k步就要停下来,停下的这个位置的奶酪数只能比上一个停留的位置大,并获取其奶酪,每次只能水平或垂直走,问最多能得到的奶酪. 解题思路:记忆化搜索,这方面还是写的太少,还要看别人才会,这个就当个例子参考吧. 1 #include<cstdio> 2 #include<cstring> 3 #include

hdu1331&amp;&amp;hdu1579记忆化搜索(DP+DFS)

这两题是一模一样的``` 题意:给了一系列递推关系,但是由于这些递推很复杂,所以递推起来要花费很长的时间,所以我要编程序在有限的时间内输出答案. w(a, b, c): 如果a,b,c中有一个值小于等于0,那么w(a, b, c)的值为1 如果a,b,c中有一个值大于20,那么w(a, b, c)的值为w(20, 20, 20) 如果a<b<c,那么w(a, b, c)=w(a, b, c-1) + w(a, b-1, c-1) - w(a, b-1, c) 否则w(a, b, c)=w(a-

HDU 1978 How many ways(第一道记忆化搜索+DP)

How many ways Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 4610    Accepted Submission(s): 2726 Problem Description 这是一个简单的生存游戏,你控制一个机器人从一个棋盘的起始点(1,1)走到棋盘的终点(n,m).游戏的规则描述如下: 1.机器人一开始在棋盘的起始点并

HNU OJ10086 挤挤更健康 记忆化搜索DP

挤挤更健康 Time Limit: 1000ms, Special Time Limit:2500ms, Memory Limit:65536KB Total submit users: 339, Accepted users: 216 Problem 10086 : No special judgement Problem description 用边长小于N的正方形方砖(注意,不要求所有的方砖大小相同,请看样例说明)不重叠地铺满N*N的正方形房间,最少要几块方砖. Input 第一行是一个整

记忆化搜索+dp(洛谷1514 引水入城2010noip提高组)

在一个遥远的国度,一侧是风景秀美的湖泊,另一侧则是漫无边际的沙漠.该国的行政区划十分特殊,刚好构成一个N 行M 列的矩形,如上图所示,其中每个格子都代表一座城市,每座城市都有一个海拔高度. 为了使居民们都尽可能饮用到清澈的湖水,现在要在某些城市建造水利设施.水利设施有两种,分别为蓄水厂和输水站.蓄水厂的功能是利用水泵将湖泊中的水抽取到所在城市的蓄水池中. 因此,只有与湖泊毗邻的第1 行的城市可以建造蓄水厂.而输水站的功能则是通过输水管线利用高度落差,将湖水从高处向低处输送.故一座城市能建造输水站

UVA - 10891 Game of Sum(记忆化搜索 dp)

#include<cstdio> #include<cstring> #include<cmath> #include<iostream> #include<algorithm> using namespace std; int a[100+10]; int dp[120][120]; int sum[120]; int vis[120][120]; int dfs(int f,int t) { int i,j,k; if(vis[f][t]==

HDU 1078 FatMouse and Cheese (记忆化搜索+dp)

详见代码 1 #include <iostream> 2 #include <cstdio> 3 #include <cstdlib> 4 #include <memory.h> 5 using namespace std; 6 const int inf=0x3f3f3f3f; 7 int a[110][110]; 8 int dp[110][110];//表示到i,j的最大路径和 9 int dir[4][2]= {1,0,-1,0,0,1,0,-1};