HDU_1639
这个题目可以用插头dp的思想去做,由于允许多条回路,那么就只需要用0、1记录每个位置是否有插头,然后逐渐生成合法的状态并记录方案种数。
更多和插头dp相关的题目可以参考胡浩的博客:http://www.notonlysuccess.com/index.php/plug-dp-complete/。
#include<stdio.h> #include<string.h> #define HASH 10007 #define STATE 1000010 #define MAXD 15 int N, M, code[MAXD], maze[MAXD][MAXD]; struct Hashmap { int head[HASH], next[STATE], state[STATE], size; long long f[STATE]; void init() { memset(head, -1, sizeof(head)); size = 0; } void push(int st, long long ans) { int i, h = st % HASH; for(i = head[h]; i != -1; i = next[i]) if(st == state[i]) { f[i] += ans; return ; } f[size] = ans, state[size] = st; next[size] = head[h]; head[h] = size ++; } }hm[2]; void decode(int *code, int m, int st) { int i; for(i = m; i >= 0; i --) { code[i] = st & 1; st >>= 1; } } int encode(int *code, int m) { int i, st = 0; for(i = 0; i <= m; i ++) { st <<= 1; st |= code[i]; } return st; } void init() { int i, j, k; scanf("%d%d", &N, &M); memset(maze, 0, sizeof(maze)); for(i = 1; i <= N; i ++) for(j = 1; j <= M; j ++) scanf("%d", &maze[i][j]); } void shift(int *code, int m) { int i; for(i = m; i > 0; i --) code[i] = code[i - 1]; code[0] = 0; } void dpblank(int i, int j, int cur) { int k, left, up; for(k = 0; k < hm[cur].size; k ++) { decode(code, M, hm[cur].state[k]); left = code[j - 1], up = code[j]; if(left && up) { code[j - 1] = code[j] = 0; if(j == M) shift(code, M); hm[cur ^ 1].push(encode(code, M), hm[cur].f[k]); } else if(left || up) { if(maze[i][j + 1]) { code[j - 1] = 0, code[j] = 1; hm[cur ^ 1].push(encode(code, M), hm[cur].f[k]); } if(maze[i + 1][j]) { code[j - 1] = 1, code[j] = 0; if(j == M) shift(code, M); hm[cur ^ 1].push(encode(code, M), hm[cur].f[k]); } } else { if(maze[i][j + 1] && maze[i + 1][j]) { code[j - 1] = code[j] = 1; hm[cur ^ 1].push(encode(code, M), hm[cur].f[k]); } } } } void dpblock(int i, int j, int cur) { int k; for(k = 0; k < hm[cur].size; k ++) { decode(code, M, hm[cur].state[k]); code[j - 1] = code[j] = 0; if(j == M) shift(code, M); hm[cur ^ 1].push(encode(code, M), hm[cur].f[k]); } } void solve() { int i, j, cur = 0; long long ans = 0; hm[cur].init(); hm[cur].push(0, 1); for(i = 1; i <= N; i ++) for(j = 1; j <= M; j ++) { hm[cur ^ 1].init(); if(maze[i][j]) dpblank(i, j, cur); else dpblock(i, j, cur); cur ^= 1; } for(i = 0; i < hm[cur].size; i ++) ans += hm[cur].f[i]; printf("There are %I64d ways to eat the trees.\n", ans); } int main() { int t, tt; scanf("%d", &t); for(tt = 0; tt < t; tt ++) { init(); printf("Case %d: ", tt + 1); solve(); } return 0; }