原题网址:http://acm.hdu.edu.cn/showproblem.php?pid=1693
连通块的表示使用括号表示法。
1.map
1 #include <cstdio> 2 #include <algorithm> 3 #include <cstring> 4 #include <map> 5 6 typedef long long LL; 7 const int MAXRC = 15; 8 int m,n,er=-1,ec, idx=0; 9 int city[MAXRC][MAXRC]={0}, bits_at[MAXRC];// 1 is valid. 10 std::map<LL,LL> mp[2]; 11 12 inline int get_state_at(LL s, int j){ 13 return (s&bits_at[j])>>(j<<1); 14 } 15 inline LL set_state_at(LL s, int j, int b){ 16 s &= ~(bits_at[j]); 17 return s|(b<<(j<<1)); 18 } 19 inline LL set_state_at(LL s, int j, int bj, int bn){ 20 s &= ~(bits_at[j]+bits_at[j+1]); 21 s |= (bj+(bn<<2))<<(j<<1); 22 return s; 23 } 24 int find_match(LL s, int j){// c!=0 25 int c = get_state_at(s, j), d = c == 1? 1:-1, f = 0; 26 for(;;j+=d){ 27 if(get_state_at(s, j)==c) f++; 28 else if(get_state_at(s,j)) f--; 29 if(f == 0) return j; 30 } 31 return -1; 32 } 33 void dp(){ 34 idx = 0;mp[idx].clear();mp[idx][0]=1; 35 for(int i=0; i<n; ++i){ 36 for(int j=0; j<m; ++j){ 37 int cur = idx^1;// 滚动数组,要求的状态集 38 mp[cur].clear(); 39 std::map<LL,LL>::iterator it=mp[idx].begin(); 40 for(; it!=mp[idx].end(); ++it){ 41 LL ps = it->first, pn = it->second; 42 if(j == 0) ps <<=2; 43 LL sl = get_state_at(ps, j), su = get_state_at(ps, j+1); 44 if(sl == 0 && su == 0){ 45 if(!city[i][j]){// 将状态延伸到无效处 46 mp[cur][set_state_at(ps, j, 0, 0)] += pn; 47 }// 插头应该指向空白的格子 48 else if(city[i][j+1] && city[i+1][j]){ 49 mp[cur][set_state_at(ps, j, 1, 2)] += pn; 50 } 51 } 52 else if(sl == 0 || su == 0){// 只延伸一个插头 53 if(city[i][j+1]) 54 mp[cur][set_state_at(ps, j, 0, sl+su)] += pn; 55 if(city[i+1][j]) 56 mp[cur][set_state_at(ps, j, sl+su, 0)] += pn; 57 } 58 else if(sl == su){// 合并连通块,同时左括号或右括号 59 int posl = find_match(ps, j), posu = find_match(ps, j+1); 60 int mn = std::min(posl, posu), mx = std::max(posl, posu); 61 LL cs = set_state_at(ps, mn, 1); 62 cs = set_state_at(cs, mx, 2); 63 mp[cur][set_state_at(cs, j, 0, 0)] += pn; 64 } 65 else{// 合并成回路 66 mp[cur][set_state_at(ps, j, 0, 0)] += pn; 67 } 68 } 69 idx = cur;// 交换状态 70 } 71 } 72 } 73 int main(){ 74 freopen("in.txt", "r", stdin); 75 for(int i=0; i<=14; ++i){ 76 bits_at[i] = 3<<(i<<1);// 0 is invalid, 1 is left bracket, 2 is right bracket. 77 } 78 int t, tot; 79 scanf("%d", &t); tot = t; 80 while(t--){ 81 scanf("%d%d", &n, &m); 82 for(int i=0; i<n; ++i){ 83 for(int j=0; j<m; ++j){ 84 scanf("%d", &city[i][j]); 85 } 86 } 87 dp(); 88 printf("Case %d: There are %lld ways to eat the trees. ", tot-t, mp[idx][0]); 89 } 90 return 0; 91 }