[Description]
Given an n * m gird that has some blocked cells. Find how many paths visit each unblocked cell exactly once from the left low cell to the right low cell in that map.

有个 n,m列的网格 ,有的格子有障碍物 ,其他的则可以行走 .问有多少条从左下角到右下角的路满足 :路经过了所有的可以行走的格子恰好一次 .

[Solution]
标准的基于连通性状态压缩DP问题。以格子一步一步的DP,设计一个m+1的插头状态并记下连通性。程序比较复杂,在2008年国家集训队陈丹琦的论文《基于连通性状态压缩的动态规划问题》中有非常详尽的介绍,这里就不多说了。
丑陋的源代码:
  1  #include < iostream >
  2  #include < cstring >
  3  #include < cstdlib >
  4  #include < cstdio >
  5  using   namespace  std;
  6 
  7  #define  MODIFY(A,B) (((B)<<(((A)-1)*2)))
  8  #define  GET(S,A) (((S)>>(((A)-1)*2))&3)
  9  #define  PRIME 999983
 10 
 11  int  n,m;
 12  char  a[ 13 ][ 14 ];
 13  long   long  f[ 2 ][ 60000 ];
 14  int  now1,cnt,lin[ 60000 ],lef;
 15  int  g[ 1000000 ],next[ 100000 ],end[ 100000 ],va[ 100000 ],gcnt;
 16  int  endx,endy,startx,starty;
 17  int  gai;
 18  int  last,now;
 19 
 20  inline  int  getp( int  x)
 21  {
 22       int  t = x % PRIME;
 23       for  ( int  i = g[t];i;i = next[i])
 24           if  (x == end[i])
 25               return  va[i]; 
 26       return   0 ;
 27  }
 28 
 29  void  dfs( int  step)
 30  {
 31       if  (step > m + 1 )
 32      {
 33           if  (lef)
 34               return ;
 35          cnt ++ ; lin[cnt] = now1;
 36           int  t = now1 % PRIME;
 37          gcnt ++ ; end[gcnt] = now1; va[gcnt] = cnt; next[gcnt] = g[t]; g[t] = gcnt;
 38           return ;
 39      }
 40      dfs(step + 1 );
 41 
 42      lef ++
 43       if  (lef <= ((m + 1 ) >> 1 ))
 44      {
 45          now1 += ( 1 << ((step - 1 ) * 2 ));
 46          dfs(step + 1 );
 47          now1 -= ( 1 << ((step - 1 ) * 2 ));
 48      }
 49      lef -- ;
 50 
 51       if  (lef)
 52      {
 53          lef -- ;
 54          now1 += ( 2 << ((step - 1 ) * 2 ));
 55          dfs(step + 1 );
 56          now1 -= ( 2 << ((step - 1 ) * 2 ));
 57          lef ++ ;
 58      }
 59  }
 60 
 61  void  prework()
 62  {
 63      dfs( 1 );
 64       int  tol = 0 ;
 65       for  ( int  i = 1 ;i <= n;i ++ )
 66           for  ( int  j = 1 ;j <= m;j ++ )
 67               if  (a[i][j] == ' . ' )
 68                  tol ++ ;
 69       if  (tol == 1 )
 70      {
 71          printf( " 0\n " );
 72          exit( 0 );
 73      }
 74       bool  flag = true ;
 75       for  ( int  i = 1 ;i <= n;i ++ )
 76      {
 77           for  ( int  j = 1 ;j <= m;j ++ )
 78               if  (a[i][j] == ' . ' )
 79              {
 80                   if  (j == m)
 81                  {
 82                      printf( " 0\n " );
 83                      exit( 0 );
 84                  }
 85                   int  t = 0 ;
 86                  t += MODIFY(j, 1 ) + MODIFY(j + 1 , 2 );
 87                  f[ 1 ][getp(t)] = 1 ;
 88                  startx = i; starty = j;
 89                  flag = false ;
 90                   break ;
 91              }
 92           if  ( ! flag)
 93               break ;
 94      }
 95      flag = true ;
 96       for  ( int  i = n;i >= 1 ;i -- )
 97      {
 98           for  ( int  j = m;j >= 1 ;j -- )
 99               if  (a[i][j] == ' . ' )
100              {
101                  endx = i; endy = j;
102                  flag = false ;
103                   break ;
104              }
105           if  ( ! flag)
106               break ;
107      }
108       if  (endy == 1 )
109      {
110          printf( " 0\n " );
111          exit( 0 );
112      }
113  }
114 
115  long   long  ans;
116 
117  void  refresh( int  x, int  y, int  _s)
118  {
119       long   long  zhi = f[last][_s];
120       int  s = lin[_s];
121      y ++
122       if  (y > m) {y = 1 ;x ++ ;}
123       if  (x == endx  &&  y == endy)
124      {
125           int  t1 = MODIFY( 1 , 1 ) + MODIFY(m + 1 , 2 );
126           int  t2 = MODIFY( 1 , 1 ) + MODIFY(m, 2 );
127           if  (s == t1  ||  s == t2)
128              ans += zhi;
129           return ;
130      }
131       if  (y == 1
132      {
133           if  (a[x][y] == ' # ' )
134          {
135               if  (GET(s, 1 ) == 0 )
136              {
137                   int  news = ((s << 2 ) & gai);
138                  f[now][getp(news)] += zhi;
139              }
140          }
141           else
142          {
143               if  (GET(s, 1 ) == 0 )
144              {
145                   int  news = ((s << 2 ) & gai);
146                  news += MODIFY( 1 , 1 ) + MODIFY( 2 , 2 );
147                  f[now][getp(news)] += zhi;
148              }
149               else
150              {
151                   int  news = (((s - MODIFY( 1 , 1 )) << 2 ) & gai);
152                  f[now][getp(news + MODIFY( 1 , 1 ))] += zhi;
153                  f[now][getp(news + MODIFY( 2 , 1 ))] += zhi;
154              }
155          }
156      }
157       else
158      {
159           if  (a[x][y] == ' # ' )
160          {
161               if  (GET(s,y) == 0   &&  GET(s,y + 1 ) == 0 )
162                  f[now][getp(s)] += zhi;
163          }
164           else
165          {
166               int  t1 = GET(s,y),t2 = GET(s,y + 1 );
167               if  (t1 != 0   &&  t2 != 0 )
168              {
169                   if  (t1 == 1   &&  t2 == 1 )
170                  {
171                       int  news = s - MODIFY(y, 1 ) - MODIFY(y + 1 , 1 );
172                       int  left = 0 ;
173                       for  ( int  i = y + 2 ;i <= m + 1 ;i ++ )
174                           if  (GET(news,i) == 1 )
175                              left ++ ;
176                           else   if  (GET(news,i) == 2 )
177                          {
178                               if  ( ! left)
179                              {
180                                  news = news - MODIFY(i, 2 ) + MODIFY(i, 1 );
181                                   break ;
182                              }
183                              left -- ;
184                          }
185                      f[now][getp(news)] += zhi;
186                  } 
187                   else   if  (t1 == 2   &&  t2 == 1 )
188                  {
189                       int  t = getp(s - MODIFY(y, 2 ) - MODIFY(y + 1 , 1 ));
190                      f[now][t] += zhi;
191                  }
192                   else   if  (t1 == 2   &&  t2 == 2 )
193                  {
194                       int  news = s - MODIFY(y, 2 ) - MODIFY(y + 1 , 2 );
195                       int  left = 0 ;
196                       for  ( int  i = y - 1 ;i >= 1 ;i -- )
197                           if  (GET(news,i) == 2 )
198                              left ++ ;
199                           else   if  (GET(news,i) == 1 )
200                          {
201                               if  ( ! left)
202                              {
203                                  news = news - MODIFY(i, 1 ) + MODIFY(i, 2 );
204                                   break ;
205                              }
206                              left -- ;
207                          }
208                      f[now][getp(news)] += zhi;
209                  }
210              }
211               if  (t1 == 0   &&  t2 != 0   &&  y != m)
212                  f[now][getp(s)] += zhi;
213               if  (t1 != 0   &&  t2 == 0   &&  x != n)
214                  f[now][getp(s)] += zhi;
215               if  (t1 == 0   &&  t2 == 0   &&  y != &&  x != n)
216                  f[now][getp(s + MODIFY(y, 1 ) + MODIFY(y + 1 , 2 ))] += zhi;
217               if  (t1 == 0   &&  t2 != 0   &&  x != n)
218                  f[now][getp(s - MODIFY(y + 1 ,t2) + MODIFY(y,t2))] += zhi;
219               if  (t1 != 0   &&  t2 == 0   &&  y != m)
220                  f[now][getp(s - MODIFY(y,t1) + MODIFY(y + 1 ,t1))] += zhi;
221          }
222      }
223  }
224 
225  void  work()
226  {
227      ans = 0 ;
228       int  i = startx,j = starty;
229      now = 0 ,last = 1 ;
230       while  ( true )
231      {
232          memset(f[now] + 1 , 0 , sizeof ( long   long ) * cnt);
233           if  (i == endx  &&  j == endy)
234               break ;
235           else
236               for  ( int  k = 1 ;k <= cnt;k ++ )
237                   if  (f[last][k])
238                      refresh(i,j,k);
239          j ++ if  (j > m) {i ++ ;j = 1 ;}
240          now ^= 1 ; last ^= 1 ;
241      }
242      printf( " %I64d\n " ,ans);
243  }
244 
245  void  init()
246  {
247      n = m = 0 ;
248      memset(a, 0 , sizeof (a));
249      memset(f, 0 , sizeof (f));
250      now1 = cnt = lef = 0 ;
251      gcnt = 0 ;
252      memset(g, 0 , sizeof (g));
253      endx = endy = startx = starty = 0 ;
254      gai = 0 ;
255      last = now = 0 ;
256      ans = 0 ;
257  }
258 
259  int  main()
260  {
261       while  ( true )
262      {
263          init();
264          scanf( " %d%d " , & n, & m);
265           if  (n == 0 break ;
266           for  ( int  i = 1 ;i <= n;i ++ )
267              scanf( " %s " ,a[i] + 1 );
268          gai = ( 1 << ((m + 1 ) * 2 )) - 1 ;
269          prework();
270          work();
271      }
272  }