码迷,mamicode.com
首页 > 其他好文 > 详细

【GDKOI 2016】地图 map 类插头DP

时间:2017-04-23 20:21:34      阅读:265      评论:0      收藏:0      [点我收藏+]

标签:gdk   str   sizeof   分享   sed   ++i   连通块   algo   tin   

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\n", ans);
137 }
138 
139 int main()
140 {
141     in();
142     work();
143     return 0;
144 }
View Code

 

【GDKOI 2016】地图 map 类插头DP

标签:gdk   str   sizeof   分享   sed   ++i   连通块   algo   tin   

原文地址:http://www.cnblogs.com/-ZZB-/p/6753631.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!