Ural 1519 Formula 1 插头DP

  这是一道经典的插头DP单回路模板题。

  用最小表示法来记录连通性,由于二进制的速度,考虑使用8进制。

  1、当同时存在左、上插头的时候,需要判断两插头所在连通块是否相同,若相同,只能在最后一个非障碍点相连;若不相同,则把这两个连通块连起来。

  2、如果只存在左或上插头的时候,则要延续连通块。

  3、若都不存在左和上插头的时候,就要新建一个连通块。

  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 = 15, HASH = 30007, STATE = 100010;
 14 int n, m, maze[MAXD][MAXD], code[MAXD], ch[MAXD], end_x, end_y;
 15 char str[MAXD];
 16 struct HASHMAP
 17 {
 18     int head[HASH], nxt[STATE], siz; LL f[STATE], state[STATE];
 19     void clear() { siz = 0, mset(head, -1); }
 20     void push(LL x, LL add)
 21     {
 22         int pos = x%HASH, i = head[pos];
 23         for (; i != -1; i = nxt[i])
 24             if (state[i] == x) { f[i] += add; return ; }
 25         state[siz] = x, f[siz] = add;
 26         nxt[siz] = head[pos], head[pos] = siz++;
 27     }
 28 }hm[2];
 29 
 30 void in()
 31 {
 32     scanf("%d %d", &n, &m), mset(maze, 0), end_x = end_y = -1;
 33     REP(i, 1, n)
 34     {
 35         scanf("%s", str+1);
 36         REP(j, 1, m) 
 37             if (str[j] == '.')
 38                 maze[i][j] = 1, end_x = i, end_y = j;
 39     }
 40 }
 41 
 42 void decode(LL x)
 43 {
 44     REP(i, 0, m) code[i] = x&7, x >>= 3;
 45 }
 46 
 47 LL encode()
 48 {
 49     LL ret = 0; int cnt = 0;
 50     mset(ch, -1), ch[0] = 0;
 51     DWN(i, m, 0) 
 52     {
 53         if (ch[code[i]] == -1) ch[code[i]] = ++cnt;
 54         ret <<= 3, ret |= ch[code[i]];
 55     }
 56     return ret;
 57 }
 58 
 59 void shift(int j)
 60 {
 61     if (j != m) return ;
 62     DWN(i, m, 1) code[i] = code[i-1];
 63     code[0] = 0;
 64 }
 65 
 66 void dp_blank(int i, int j, int cur)
 67 {
 68     REP(k, 0, hm[cur].siz-1)
 69     {
 70         decode(hm[cur].state[k]);
 71         int lef = code[j-1], up = code[j];
 72         if (lef && up)
 73         {
 74             if (lef == up && !(i == end_x && j == end_y)) continue ;
 75             REP(t, 0, m)
 76                 if (code[t] == up) code[t] = lef;
 77             code[j-1] = code[j] = 0, shift(j);
 78             hm[cur^1].push(encode(), hm[cur].f[k]);
 79         }
 80         else
 81             if (lef || up)
 82             {
 83                 int t = lef ? lef : up;
 84                 if (maze[i][j+1])
 85                 {
 86                     code[j-1] = 0, code[j] = t;
 87                     hm[cur^1].push(encode(), hm[cur].f[k]);
 88                 }
 89                 if (maze[i+1][j])
 90                 {
 91                     code[j-1] = t, code[j] = 0, shift(j);
 92                     hm[cur^1].push(encode(), hm[cur].f[k]);
 93                 }
 94             }
 95             else
 96                 if (maze[i][j+1] && maze[i+1][j])
 97                 {
 98                     code[j-1] = code[j] = 13, shift(j);
 99                     hm[cur^1].push(encode(), hm[cur].f[k]);
100                 }
101     }
102 }
103 
104 void dp_block(int i, int j, int cur)
105 {
106     REP(k, 0, hm[cur].siz-1)
107     {
108         decode(hm[cur].state[k]), shift(j);
109         hm[cur^1].push(encode(), hm[cur].f[k]);
110     }
111 }
112 
113 void work()
114 {
115     int cur = 0; LL ans = 0;
116     hm[0].clear(), hm[1].clear(), hm[cur].push(0, 1);
117     REP(i, 1, n)
118         REP(j, 1, m)
119         {
120             if (maze[i][j]) dp_blank(i, j, cur);
121             else dp_block(i, j, cur);
122             hm[cur].clear(), cur ^= 1;
123         }
124     REP(i, 0, hm[cur].siz-1) ans += hm[cur].f[i];
125     printf("%I64d\n", ans);
126 }
127 
128 int main()
129 {
130     in();
131     work();
132     return 0;
133 }
View Code

 

posted @ 2017-02-23 19:34  Splay  阅读(292)  评论(0编辑  收藏  举报