【插头DP】HDU 4285 circuits

通道:http://acm.hdu.edu.cn/showproblem.php?pid=4285

题意:多回路, 有障碍K回路问题。

代码:

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <algorithm>
  4
  5 using namespace std;
  6
  7 const int MAX_N = 13;
  8 const int MAX_M = 13;
  9 const int HASH = 300007;
 10 const int MAX_S = 1000007 + 10;
 11 const int MOD = 1000000007;
 12
 13
 14 const int mov[20] = {0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30};
 15
 16 struct node {
 17     int head[HASH], nxt[MAX_S];
 18     long long dp[MAX_S], st[MAX_S];
 19     long long num[MAX_S];
 20     int cnt;
 21     void init() {
 22         memset(head, -1, sizeof head);
 23         cnt = 0;
 24     }
 25     void push(long long s, long long v, long long val) {
 26         int now = s % HASH;
 27         for(int i = head[now]; ~i; i = nxt[i]) if(st[i] == s && val == num[i]) {
 28             dp[i] = (dp[i] + v) % MOD;
 29             return ;
 30         }
 31         st[cnt] = s; dp[cnt] = v;  num[cnt] = val;
 32         nxt[cnt] = head[now];
 33         head[now] = cnt++;
 34     }
 35 }d[2];
 36
 37 int n, m, K;
 38
 39 int find_pos(long long s, int p) {
 40     return (s >> (p << 1)) & 3;
 41 }
 42
 43 void tp(long long &s, int p, long long v) {
 44     s &= (~(3ll << (p << 1)));
 45     s |= (v << (p << 1));
 46 }
 47
 48 int find_r(long long s, int p) {
 49     int cnt = 0;
 50     for(int i = p; i <= m; ++i) {
 51         if(find_pos(s, i) == 1) ++cnt;
 52         else if(find_pos(s, i) == 2) --cnt;
 53         if(!cnt) return i;
 54     }
 55 }
 56
 57 int find_l(long long s, int p) {
 58     int cnt = 0;
 59     for(int i = p; i >= 0; --i) {
 60         if(find_pos(s, i) == 2) ++cnt;
 61         else if(find_pos(s, i) == 1) --cnt;
 62         if(!cnt) return i;
 63     }
 64 }
 65
 66 void blank(int i, int j, int cur) {
 67     for(int k = 0; k < d[cur].cnt; ++k) {
 68         long long t = d[cur].st[k];
 69         int l = find_pos(t, j - 1), r = find_pos(t, j);
 70         if(l && r) {
 71             if(l == 1 && r == 1) {
 72                 int tpos = find_r(t, j);
 73                 tp(t, j - 1, 0); tp(t, j, 0); tp(t, tpos, 1);
 74                 d[cur ^ 1].push(t, d[cur].dp[k], d[cur].num[k]);
 75             } else if(l == 2 && r == 1) {
 76                 tp(t, j - 1, 0); tp(t, j, 0);
 77                 d[cur ^ 1].push(t, d[cur].dp[k], d[cur].num[k]);
 78             } else if(l == 2 && r == 2) {
 79                 int tpos = find_l(t, j - 1);
 80                 tp(t, j - 1, 0); tp(t, j, 0); tp(t, tpos, 2);
 81                 d[cur ^ 1].push(t, d[cur].dp[k], d[cur].num[k]);
 82             } else {
 83                 int count = 0;
 84                 for (int z = j - 2; z >= 0; --z) if (find_pos(t, z)) ++count;
 85                 if (count & 1) continue;
 86                 for (int z = j + 1; z <= m; ++z) if (find_pos(t, z)) ++count;
 87                 if (count & 1) continue;
 88                 tp(t, j - 1, 0); tp(t, j, 0);
 89                  d[cur ^ 1].push(t, d[cur].dp[k], d[cur].num[k] + 1);
 90             }
 91         } else if(l) {
 92             if(i < n) {
 93                 d[cur ^ 1].push(t, d[cur].dp[k], d[cur].num[k]);
 94             }
 95             if(j < m) {
 96                 tp(t, j - 1, 0); tp(t, j, l);
 97                 d[cur ^ 1].push(t, d[cur].dp[k], d[cur].num[k]);
 98             }
 99         } else if(r) {
100             if(j < m) {
101                 d[cur ^ 1].push(t, d[cur].dp[k], d[cur].num[k]);
102             }
103             if(i < n) {
104                 tp(t, j - 1, r); tp(t, j, 0);
105                 d[cur ^ 1].push(t, d[cur].dp[k], d[cur].num[k]);
106             }
107         } else { // 新建
108             if(i < n && j < m) {
109                 tp(t, j - 1, 1); tp(t, j, 2);
110                 d[cur ^ 1].push(t, d[cur].dp[k], d[cur].num[k]);
111             }
112         }
113     }
114 }
115
116 void block(int i, int j, int cur) {
117     for (int k = 0; k < d[cur].cnt; ++k) {
118         long long t = d[cur].st[k];
119         int l = find_pos(t, j - 1), r = find_pos(t, j);
120         if (!l && !r) d[cur ^ 1].push(t, d[cur].dp[k], d[cur].num[k]);
121     }
122 }
123
124 char str[17];
125 int a[MAX_N][MAX_M];
126
127 int main() {
128     int T;
129     scanf("%d", &T);
130     while (T-- > 0) {
131         scanf("%d%d%d", &n, &m, &K);
132         memset(a, 0, sizeof a);
133         int ex = -1;
134         for (int i = 1; i <= n; ++i) {
135             scanf("%s", str + 1);
136             for (int j = 1; j <= m; ++j) {
137                 if (str[j] == ‘.‘) {
138                     a[i][j] = 1;
139                     ex = i;
140                 }
141             }
142         }
143         if (ex == -1) {
144             if (K == 0) puts("1");
145             else puts("0");
146         } else {
147             int cur = 0;
148             d[cur].init();
149             memset(d[cur].num, 0, sizeof d[cur].num);
150             d[cur].push(0, 1, 0);
151             long long ans = 0;
152             for (int i = 1; i <= n; ++i) {
153                 for (int j = 1; j <= m; ++j) {
154                     d[cur ^ 1].init();
155                     if (a[i][j]) blank(i, j, cur);
156                     else block(i, j, cur);
157                     cur ^= 1;
158                 }
159                 for(int k = 0; k < d[cur].cnt; ++k) {
160                     d[cur].st[k] <<= 2;
161                 }
162             }
163          //   for (int i = 0; i < d[cur].cnt; ++i)
164            //     printf("%d %d %d %d\n", i, d[cur].st[i], d[cur].st[i] >> mov[m + 2], d[cur].dp[i]);
165             for (int i = 0; i < d[cur].cnt; ++i) if (d[cur].num[i] == K)
166                 ans = (ans + d[cur].dp[i]) % MOD;
167             printf("%I64d\n", ans);
168         }
169     }
170     return 0;
171 }
172
173 /*
174
175 100
176
177 4 4 1
178 **..
179 ....
180 ....
181 ....
182
183 4 4 1
184 ....
185 ....
186 ....
187 ....
188
189 4 4 2
190 ....
191 ....
192 ....
193 ....
194
195 4 4 4
196 ....
197 ....
198 ....
199 ....
200
201 */

TAG:控制好HASH啊。

时间: 2024-08-09 19:51:36

【插头DP】HDU 4285 circuits的相关文章

HDU 4285 circuits

插头DP. 题目要求构造出K条回路的方案数,而且不能出现环套环. Sol:通过增加标记为来记录形成的回路数,假如不形成环的话就是在形成新的环路,此时,两边的插头个数要为偶数. #include<stdio.h> #include<iostream> #include<algorithm> #include<string.h> using namespace std; const int MAXD=15; const int STATE=1000010; co

hdu 1693 Eat the Trees (插头dp入门)

Eat the Trees Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 2507    Accepted Submission(s): 1225 Problem Description Most of us know that in the game called DotA(Defense of the Ancient), Pudg

HDU 4113 Construct the Great Wall(插头dp)

好久没做插头dp的样子,一开始以为这题是插头,状压,插头,状压,插头,状压,插头,状压,无限对又错. 昨天看到的这题. 百度之后发现没有人发题解,hust也没,hdu也没discuss...在acm-icpc信息站发现难得的一篇题解.不过看到是插头二字之后,代码由于风格太不一样就没看了,自己想了好久,想通了.然后就等到今天才码.... 如果把点看成网格,那就可以实现,没有公共点公共边等限定条件,也显然是插头dp的最短单回路的模型.这是本题的一个难点(当时想到这样是因为,题目要求计算最短周长,显然

HDU 1693 Eat the Trees 插头DP

链接:http://acm.hdu.edu.cn/showproblem.php?pid=1693 题意:给出一块r*c的地,(r,c<=11),其中有的土地上种上了树,有些没有种上树,只能在种上树的地上走,通过走若干个回路,来走遍所有种树的土地.问有多少种走法. 思路:无论如何还是要先提供一个链接:http://wenku.baidu.com/view/4fe4ac659b6648d7c1c74633.html,是国家队论文,里面对于要提及的概念讲解的十分清楚. dp的过程是从左上角的点到右下

HDU 4804 Campus Design(插头DP)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4804 题意:给定一个图,0是不能放的,然后现在有1X1和1X2方块,最后铺满该图,使得1X1使用次数在C到D之间,1X2次数随便,问有几种放法 思路:插头DP的变形,只要多考虑1X1的情况即可,然后DP多开一维表示使用1X1的个数 代码: #include <stdio.h> #include <string.h> #include <algorithm> #include

hdu 4804 Campus Design(插头dp)

题目链接:hdu 4804 Campus Design 题目大意:有1?2的木块无穷个,要求在给定的图n?m的图上,用1?2和1?1的木块铺满,图上的0表示不需要铺的位置,1表示必须要铺的位置.并且1?1的使用数量必须在c到d之间.求总方案数. 解题思路:和uva11270一样的做法,只是需要多添加一位状态来表示用掉1得个数,以及要对当前位置判断是否为可放. #include <cstdio> #include <cstring> #include <algorithm>

HDU 4949 Light(插头dp、位运算)

比赛的时候没看题,赛后看题觉得比赛看到应该可以敲的,敲了之后发现还真就会卡题.... 因为写完之后,无限TLE... 直到后来用位运算代替了我插头dp常用的decode.encode.shift三个函数以及改改HASH值才勉强过的...7703ms 题意:给一个N*M的01矩阵,每次可以选一个格子进行2种操作,①翻转邻居格子②翻转邻居格子和自己.输出最小的总操作数使得矩阵全为0. 显然每个格子有4种操作(一.不操作:二.①②:三.①:四.②). 一开始写的时候用2位表示一个插头,一位用于表示翻转

HDU 3377 Plan (插头DP,变形)

题意:有一个n*m的矩阵,每个格子中有一个值(可能负值),要从左上角走到右下角,求路径的最大花费. 思路: 除了起点和终点外,其他的点可以走,也可以不走. (2)我用的是括号表示法,所以起始状态为')',即仅有一个右括号,那么到右下角也应该是只有一个右括号.因为,如果碰到()),加粗表示起点的那个右括号,那么合并后变成)##,仍然是右括号,如果是)(),那么合并后变成##),仍然是右括号,相当于延续了.插头每到达一个格子就先将其值给加上,如果要合并的时候,再减掉(因为多算了一次),因此,新括号的

插头DP专题

建议入门的人先看cd琦的<基于连通性状态压缩的动态规划问题>.事半功倍. 插头DP其实是比较久以前听说的一个东西,当初是水了几道水题,最近打算温习一下,顺便看下能否入门之类. 插头DP建议先理解“插头”的概念.然后会HASH表(这个其实是很基础的东西,应该都会的).然后就是DP. 以及特殊题目的特殊处理. 好像一般是求N,M<=12的网格图的某种回路数或某种通路数的方案数. 大体上每个题说几句特殊处理,有问题请纠正....题目的顺序基本上难度递增 另外代码我都是用括号匹配的.因为感觉连通