hdu1693Eat the trees(插头dp)

原题网址: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.\n", tot-t, mp[idx][0]);
89     }
90     return 0;
91 }

 

posted @ 2016-08-09 15:40  Keep_Going  阅读(153)  评论(0编辑  收藏  举报