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;}
- FZ_2011 Carcassonne 状态DP
- HDU4064 Carcassonne(状态压缩DP)
- [状压dp] hdu 4064 Carcassonne
- Carcassonne - HDU 4064 状压dp
- hdu 4064 Carcassonne(DP-插头DP)
- hdu 4064Carcassonne——11年福州网络赛状压dp
- 状态DP
- hdu 4064 Carcassonne
- ZZ 状态DP
- pku 1185[状态dp]
- 状态压缩dp
- pku1038状态压缩dp
- 状态压缩DP 入门
- HDU1074 状态压缩DP
- Poj3254 状态压缩DP
- 状态压缩DP入门
- poj1185 状态dp
- 状态dp 第一道
- JAVA实现SFTP上传,下载,删除等方法
- 远程桌面连接提示“您的凭据不工作”
- maven 1.x plugin无法输出使用commongs-logging打印的日志
- 网络编程之入门篇(一)
- asp.net 后台判断显示,读取数据库内容
- FZ_2011 Carcassonne 状态DP
- 如何查看linux命令源代码
- Javascript面向对象编程(二):构造函数的继承
- 关于默读
- Qt 简易电子相册
- 谈谈对APC的一点理解
- 【树形DP】爱心蜗牛
- Flex文件上传
- 定制替换Android桌面(home screen)