• UVA 10531 Maze Statistics 迷宫统计 迷宫插头DP 四联通 概率


      题意:

        有一个N*M的图,每个格子有独立概率p变成障碍物。你要从迷宫左上角走到迷宫右下角。求每个格子成为一个有解迷宫中的障碍物的概率。N <= 5,M <= 6

      分析:

        这真是一道好题,网上几乎没有任何关于四连通的插头DP的任何资料,这道题目很好地反映了这类问题。

        四连通中,只要你存在了右插头,必然存在下插头,当然,你的插头不一定需要真正连到可行格子中,因此在当前行中你只需要记录右插头。

        但是不是需要换行的吗?由于下插头跟右插头是同时存在的,那么我们只需要把右插头当做下插头来用就可以了,是不是比普通的简单路径的插头dp简单很多?

        来,我们看一下转移吧,其实情况的分类还是跟普通的插头dp一样的,不得不说cdq的插头普适性真是厉害。

        1、同时存在左插头和上插头,那么只需要把连通块连一下,然后记一个右插头。

        2、只存在左插头或者上插头,那么只需要延续连通块,再记一个右插头。

        3、都不存在左插头和上插头,那么只需要新建一个连通块,记在右插头。

        而换行操作,只需要把右插头变成下插头就可以了。

      程序:(学习了某岛大神的代码之后才写出来了这份代码)

      1 #include <cstdio>
      2 #include <cstdlib>
      3 #include <cstring>
      4 #include <string>
      5 #include <algorithm>
      6 #include <iostream>
      7 
      8 using namespace std;
      9 
     10 typedef long long LL;
     11 const int HASH = 30007;
     12 const int STATE = 1000010;
     13 const int MAXD = 15;
     14 const double EPS = 1e-15;
     15 int n, m;
     16 double maze[MAXD][MAXD];
     17 int code[MAXD], ch[MAXD];
     18 
     19 int fcmp(double x)
     20 {
     21     return x < -EPS ? -1 : x > EPS;
     22 }
     23 
     24 void decode(LL st)
     25 {
     26     int i;
     27     for (i = m; i >= 0; --i)
     28     {
     29         code[i] = st&7;
     30         st >>= 3;
     31     }
     32 }
     33 
     34 LL encode()
     35 {
     36     LL st = 0;
     37     int i, cnt = 1;
     38     memset(ch, -1, sizeof(ch));
     39     ch[0] = 0, ch[1] = 1;
     40     for (i = 0; i <= m; ++i)
     41     {
     42         if (ch[code[i]] == -1)
     43             ch[code[i]] = ++cnt;
     44         code[i] = ch[code[i]];
     45         st <<= 3;
     46         st |= code[i];
     47     }
     48     return st;
     49 }
     50 
     51 struct HASHMAP
     52 {
     53     int head[HASH], next[STATE], size;
     54     LL state[STATE];
     55     double f[STATE];
     56     void clear()
     57     {
     58         size = 0;
     59         memset(head, -1, sizeof(head));
     60     }
     61     void push(LL st, double ans)
     62     {
     63         int i;
     64         decode(st);
     65         for (i = 0; i <= m; ++i)
     66             if (code[i] == 1)
     67                 break ;
     68         if (i == m+1) //如果编号为1的连通块不存在,那就不可行
     69             return ;
     70         int x = st%HASH;
     71         for (i = head[x]; i != -1; i = next[i])
     72             if (st == state[i])
     73             {
     74                 f[i] += ans;
     75                 return ;
     76             }
     77         f[size] = ans;
     78         state[size] = st;
     79         next[size] = head[x];
     80         head[x] = size ++;
     81     }
     82 }hm[2];
     83 
     84 void in()
     85 {
     86     int i, j;
     87     scanf("%d %d", &n, &m);
     88     for (i = 1; i <= n; ++i)
     89         for (j = 1; j <= m; ++j)
     90             scanf("%lf", &maze[i][j]);
     91 }
     92 
     93 void dp_blank(int i, int j, int cur)
     94 {
     95     if (!fcmp(1.0-maze[i][j]))
     96         return ;
     97     int k, lef, up, t;
     98     for (k = 0; k < hm[cur].size; ++k)
     99     {
    100         if (!fcmp(hm[cur].f[k]))
    101             continue ;
    102         decode(hm[cur].state[k]);
    103         lef = code[j-1], up = code[j];
    104         if (lef && up)//分类讨论只对右插头做修改
    105         {
    106             if (lef != up)
    107             {
    108                 if (lef < up)
    109                     swap(lef, up);
    110                 for (t = 0; t <= m; ++t)
    111                     if (code[t] == lef)
    112                         code[t] = up;
    113             }
    114         }
    115         else
    116         {
    117             if (lef || up)
    118                 code[j] = lef|up;
    119             else
    120                 code[j] = m+1;
    121         }
    122         hm[cur^1].push(encode(), hm[cur].f[k]*(1.0-maze[i][j]));
    123     }
    124 }
    125 
    126 void dp_block(int i, int j, int cur)
    127 {
    128     if (!fcmp(maze[i][j]))
    129         return ;
    130     int k;
    131     for (k = 0; k < hm[cur].size; ++k)
    132     {
    133         if (!fcmp(hm[cur].f[k]))
    134             continue ;
    135         decode(hm[cur].state[k]);
    136         code[j] = 0;//同理
    137         hm[cur^1].push(encode(), hm[cur].f[k]*maze[i][j]);
    138     }
    139 }
    140 
    141 double solve()
    142 {
    143     int i, j, cur = 0;
    144     memset(code, 0, sizeof(code));
    145     hm[cur].clear();
    146     code[1] = 1;
    147     hm[cur].push(encode(), 1);
    148     for (i = 1; i <= n; ++i)
    149         for (j = 1; j <= m; ++j)
    150         {
    151             hm[cur^1].clear();
    152             dp_blank(i, j, cur);
    153             dp_block(i, j, cur);
    154             cur ^= 1;
    155         }
    156     double ret = 0;
    157     for (i = 0; i < hm[cur].size; ++i)
    158     {
    159         decode(hm[cur].state[i]);
    160         if (code[m] == 1)
    161             ret += hm[cur].f[i];
    162     }
    163     return ret;
    164 }
    165 
    166 void work()
    167 {
    168     int i, j;
    169     double sum = solve();
    170     for (i = 1; i <= n; ++i)
    171         for (j = 1; j <= m; ++j)
    172         {
    173             double cache = maze[i][j];
    174             maze[i][j] = 1.0;
    175             printf("%.6lf%c", solve()*cache/sum, (j == m) ? '
    ' : ' ');
    176             maze[i][j] = cache;
    177         }
    178 }
    179 
    180 int main() 
    181 {
    182     int T, iCase = 0;
    183     scanf("%d", &T);
    184     while (T --)
    185     {
    186         if (iCase++)
    187             printf("
    ");
    188         in();
    189         work();
    190     }
    191     return 0;
    192 }
  • 相关阅读:
    VM虚拟机Linux和主机数据传输
    Linux CentOS 虚拟机下联网
    SQL 注入漏洞
    BurpSuite 各模块使用
    御剑指纹识别
    C#数组2(多维数组)
    C#数组1
    C#简单的枚举及结构
    ABAP性能1 | LOOP嵌套LOOP代码分析 (转)
    占位符使用(竖式计算)
  • 原文地址:https://www.cnblogs.com/-ZZB-/p/6440040.html
Copyright © 2020-2023  润新知