FZ_2011 Carcassonne 状态DP

来源:互联网 发布:java web前端包括什么? 编辑:程序博客网 时间:2024/05/09 02:14

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 1000000007int 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;}



原创粉丝点击