• 【GDKOI 2016】地图 map 类插头DP


    Description

      对于一个n*m的地图,每个格子有五种可能:平地,障碍物,出口,入口和神器。一个有效的地图必须满足下列条件:

      1.入口,出口和神器都有且仅出现一次,并且不在同一个格子内。

      2.入口,出口和神器两两都是连通的。

      连通性判断为四连通。

      现在给出一个n*m的地图,其中一些格子的状态已经确定,另一些格子的状态未确定。

      问当所有的格子状态确定之后,有多少种情况使得该地图是一个有效的地图?输出结构为答案模1e9+7。

    Input

      第一行输入两个整数n和m,意义如题目所示。接下来n行,每行m个字符:

      字符'.'表示平地

      字符'#'表示障碍物

      字符'?'表示未确定

      字符'S'表示入口

      字符'X'表示神器

      字符'E'表示出口

    Output

      一行,表示方案数

    Sample Input

      2 3

      S#E

      ???

    Sample Output

      3

    HINT

      对于30%的数据,?数量小于10

      对于100%的数据,1<=n<=7,1<=m<=7

    Solution

      这是一道类插头DP的题目,做法与插头DP类似。

      对于'?',我们可以枚举情况;而对于其他已经确定了的状态,可以直接按格DP。

      状态只需记录格子所在的连通块,并在最后记录入口,出口和神器所在的连通块,HASH存。

    Code

      1 #include <cstdio>
      2 #include <cstdlib>
      3 #include <cstring>
      4 #include <string>
      5 #include <algorithm>
      6 
      7 using namespace std;
      8 
      9 #define REP(i, a, b) for (int i = (a), i##_end_ = (b); i <= i##_end_; ++i)
     10 #define DWN(i, a, b) for (int i = (a), i##_end_ = (b); i >= i##_end_; --i)
     11 #define mset(a, b) memset(a, b, sizeof(a))
     12 typedef long long LL;
     13 const int MAXD = 16, HASH = 30007, STATE = 100010, MOD = 1e9+7;
     14 int n, m, code[MAXD], ch[MAXD], x[3], y[3];
     15 char maze[MAXD][MAXD], sp[5] = {'S', 'X', 'E', '.', '#'};
     16 
     17 void add(LL &x, LL y) { x += y; if (x >= MOD) x -= MOD; }
     18 
     19 struct HASHMAP
     20 {
     21     int head[HASH], nxt[STATE], siz; LL state[STATE], f[STATE];
     22     void clear() { siz = 0, mset(head, -1); }
     23     void push(LL x, LL k)
     24     {
     25         int pos = x%HASH, i = head[pos];
     26         for (; i != -1; i = nxt[i])
     27             if (state[i] == x) { add(f[i], k); return ; }
     28         state[siz] = x, f[siz] = k;
     29         nxt[siz] = head[pos], head[pos] = siz++;
     30     }
     31 }hm[2];
     32 
     33 void in()
     34 {
     35     scanf("%d %d", &n, &m);
     36     mset(x, -1), mset(y, -1);
     37     REP(i, 1, n) 
     38     {
     39         scanf("%s", maze[i]+1);
     40         REP(j, 1, m)
     41         {
     42             if (maze[i][j] == 'S') x[0] = i, y[0] = j;
     43             else if (maze[i][j] == 'X') x[1] = i, y[1] = j;
     44             else if (maze[i][j] == 'E') x[2] = i, y[2] = j;
     45         }
     46     }
     47 }
     48 
     49 bool check(int i, int j)
     50 {
     51     if (maze[i][j] == 'S' && code[m+1]) return 1;
     52     else if (maze[i][j] == 'X' && code[m+2]) return 1;
     53     else if (maze[i][j] == 'E' && code[m+3]) return 1;
     54     else return 0;
     55 }
     56 
     57 void decode(LL x)
     58 {
     59     REP(i, 1, m+3) code[i] = x&7, x >>= 3;
     60 }
     61 
     62 LL encode(int i, int j)
     63 {
     64     if (maze[i][j] == 'S') code[m+1] = code[j];
     65     else if (maze[i][j] == 'X') code[m+2] = code[j];
     66     else if (maze[i][j] == 'E') code[m+3] = code[j];
     67     LL ret = 0; int cnt = 0;
     68     mset(ch, -1), ch[0] = 0;
     69     DWN(t, m+3, 1)
     70     {
     71         if (ch[code[t]] == -1) ch[code[t]] = ++cnt;
     72         ret <<= 3, ret |= ch[code[t]];
     73     }
     74     return ret;
     75 }
     76 
     77 void dp_blank(int i, int j, int cur)
     78 {
     79     REP(k, 0, hm[cur].siz-1)
     80     {
     81         decode(hm[cur].state[k]);
     82         if (check(i, j)) continue ;
     83         int lef = code[j-1], up = code[j], id = 13;
     84         if (lef) id = min(id, lef);
     85         if (up) id = min(id, up);
     86         if (lef)
     87             REP(t, 1, m+3) if (code[t] == lef) code[t] = id;
     88         if (up)
     89             REP(t, 1, m+3) if (code[t] == up) code[t] = id;
     90         code[j] = id;
     91         hm[cur^1].push(encode(i, j), hm[cur].f[k]);        
     92     }
     93 }
     94 
     95 void dp_block(int i, int j, int cur)
     96 {
     97     REP(k, 0, hm[cur].siz-1)
     98     {
     99         decode(hm[cur].state[k]), code[j] = 0;
    100         hm[cur^1].push(encode(i, j), hm[cur].f[k]);
    101     }
    102 }
    103 
    104 void work()
    105 {
    106     int cur = 0; LL ans = 0;
    107     hm[0].clear(), hm[1].clear(), hm[0].push(0, 1);
    108     REP(i, 1, n)
    109         REP(j, 1, m)
    110         {
    111             if (maze[i][j] != '?')
    112             {
    113                 if (maze[i][j] == '#') dp_block(i, j, cur);
    114                 else dp_blank(i, j, cur);
    115             }
    116             else
    117             {
    118                 REP(t, 0, 4)
    119                 {
    120                     if (t < 3 && x[t] != -1) continue ;
    121                     maze[i][j] = sp[t];
    122                     if (maze[i][j] == '#') dp_block(i, j, cur);
    123                     else dp_blank(i, j, cur);
    124                 }
    125             }
    126             hm[cur].clear(), cur ^= 1;
    127         }
    128     REP(i, 0, hm[cur].siz-1)
    129     {
    130         decode(hm[cur].state[i]);
    131         if ((!code[m+1]) || (!code[m+2]) || (!code[m+3])) continue ;
    132         int t = code[m+1];
    133         if (code[m+2] != t || code[m+3] != t) continue ;
    134         add(ans, hm[cur].f[i]);
    135     }
    136     printf("%I64d
    ", ans);
    137 }
    138 
    139 int main()
    140 {
    141     in();
    142     work();
    143     return 0;
    144 }
    View Code
  • 相关阅读:
    hdu-1698(线段树,区间修改)
    hdu-1394(线段树)
    hdu-1166(线段树)
    hdu-1251(string+map)
    hdu-1711(kmp算法)
    hdu-2191(完全背包+二进制优化模板)
    hdu-2844(完全背包+二进制优化模板)
    hdu-1171(多重背包+二进制优化)
    SpringMVC 参数中接收数组、List写法
    如何高效的查询数组中是否包含某个值
  • 原文地址:https://www.cnblogs.com/-ZZB-/p/6753631.html
Copyright © 2020-2023  润新知