http://acm.hdu.edu.cn/showproblem.php?pid=4064
题意:给定n*m给方块四边形,四边形的每边都有一种颜色,可以为R、F、C中的一种,在只可以旋转单个方块的前提下,问总共有多少种旋转方法,可以使最终的结果变成每两个共享一条边的四边形颜色一样。
算法:状态DP, 状态为:dp[row][now_s] = ∑ dp[row-1][pre_s] , 其中pre_s 到now_s 为合法转移。
复杂度分析:n,m<=12 ,用dfs求now_s的每个值,因为每个方块有四种形态, 因此复杂度为 O(n) = 4^m * n ,直接求的话会得到一个TLE,这里需要优化,即在枚举每个方块的形态的时候,将方块的形态相同的归为一类,即可以通过乘以一个系数来避免重复计算,这样的优化可以将时间降低到500ms 。
代码:
#include<stdio.h> #include<string.h> #define MOD 1000000007 int n,m,all,row,now,pre; char map[13][13][5]; long long dp[2][540000] ; int get_val(char a) { if(a == 'C') return 0 ; if(a == 'F') return 1 ; if(a == 'R') return 2 ; } bool ok(int row,int col,int i,int j) { if(map[row][col][i] != map[row][col][j]) return false ; if(map[row][col][(i+1)%4] != map[row][col][(j+1)%4]) return false ; if(map[row][col][(i+2)%4] != map[row][col][(j+2)%4]) return false ; if(map[row][col][(i+3)%4] != map[row][col][(j+3)%4]) return false ; return true ; } //V: 横向前一个方块的右边的颜色情况; col : 当前的列 ; nnum:当前行的重叠状态数 void dfs(int v,int col,int now_s, int pre_s,long long nnum) { if(col > m) { dp[now][now_s] = (dp[now][now_s] + dp[pre][pre_s]*nnum) % MOD ; return ; } bool vis[4] ; memset(vis,false,sizeof(vis)); for(int i=0;i<4;i++) //0:C 1:F 2:R { if(vis[i]) continue ; //和之前的状态重合,已经计算过了 。 if(v==3) //第一个方块,不受限制 { vis[i] = true ; int n_v = get_val(map[row][col][(i+1)%4]) ; int pre_a = get_val(map[row][col][i]); int now_a = get_val(map[row][col][(i+2)%4]); long long num = 1 ; for(int j=i+1;j<4;j++) //寻找相同的状态。 { if(ok(row,col,i,j)) { num++ ; vis[j] = true ; } } dfs(n_v,col+1,now_s*3+now_a,pre_s*3+pre_a,nnum*num) ; } else if(v==1) //横向前一个方块的右边为:F { if(v == get_val(map[row][col][(i+3)%4])) //当前方块的左边为F { vis[i] = true ; int n_v = get_val(map[row][col][(i+1)%4]) ; int pre_a = get_val(map[row][col][i]); int now_a = get_val(map[row][col][(i+2)%4]); long long num = 1 ; for(int j=i+1;j<4;j++) { if(ok(row,col,i,j)) { num++ ; vis[j] = true ; } } dfs(n_v,col+1,now_s*3+now_a,pre_s*3+pre_a,nnum*num) ; } } else if(v == 2) { if(v == get_val(map[row][col][(i+3)%4])) { vis[i] = true ; int n_v = get_val(map[row][col][(i+1)%4]) ; int pre_a = get_val(map[row][col][i]); int now_a = get_val(map[row][col][(i+2)%4]); long long num = 1 ; for(int j=i+1;j<4;j++) { if(ok(row,col,i,j)) { num++ ; vis[j] = true ; } } dfs(n_v,col+1,now_s*3+now_a,pre_s*3+pre_a,nnum*num) ; } } else if(v == 0) { if(v == get_val(map[row][col][(i+3)%4])) { vis[i] = true ; int n_v = get_val(map[row][col][(i+1)%4]) ; int pre_a = get_val(map[row][col][i]); int now_a = get_val(map[row][col][(i+2)%4]); long long num = 1 ; for(int j=i+1;j<4;j++) { if(ok(row,col,i,j)) { num++ ; vis[j] = true ; } } dfs(n_v,col+1,now_s*3+now_a,pre_s*3+pre_a,nnum*num) ; } } } } int main() { int T; scanf("%d",&T); for(int ncase=1;ncase<=T;ncase++) { printf("Case %d: ",ncase); scanf("%d %d",&n,&m); for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) { scanf("%s",map[i][j]); } } all = 1 ; //总的状态数; for(int i=1;i<=m;i++) { all *= 3 ; } for(int i=0;i<all;i++) { dp[0][i] = 1 ; } now = 0 ; pre = 1 ; //滚动数组优化空间; for(int i=1;i<=n;i++) { row = i ; now ^= 1 ; pre ^= 1 ; memset(dp[now],0,sizeof(dp[now])); dfs(3,1,0,0,1) ; } long long ans = 0 ; for(int i=0;i<all;i++) { ans = (ans + dp[now][i]) % MOD ; } printf("%lld\n",ans); } return 0; }