题目来源:http://acm.hdu.edu.cn/showproblem.php?pid=4064
/*福州网络赛的一道题,很容易看出状态压缩DP,当时用四进制写的,没能做出来,感觉会超时,赛后看别人的解题报告,可以记录上面的状态和下面的状态然后用三进制实现。
不过要加一些剪枝,比如:对于四面都一样的瓷块,只需算出一种状态,然后乘以4。这是个很有力的剪枝。*/
4730663 | 2011-10-10 10:15:52 | Accepted | 4064 | 328MS | 9640K | 1382 B | C++ | zyzamp |
这次写的方法和以前写的不同,以前都是枚举每一个状态,直接for循环搞定,而这个不能直接枚举状态,因为有的状态不存在,或者有的存在但是上下界不容易确定。
所以要用dfs,dfs结束确定一种状态。
code:
# include<stdio.h> # include<string.h> # define N 600000 # define mod 1000000007 int n,m; __int64 dp[2][N],sum; char map[15][15][5]; int a[200],tag,flag; int s[15]; void DFS(int r,int up,int down,int num,int right) { int xx,rr,yy,ll,i; if(num==m) { if(r==0) dp[flag][down]+=tag; else { dp[flag][down]+=dp[(flag+1)%2][up]*tag; dp[flag][down]%=mod; } return; } for(i=1;i<4;i++) if(map[r][num][i]!=map[r][num][0]) break; if(i==4) { tag*=4; xx=a[map[r][num][0]]; if(xx==right || right==-1) DFS(r,up*3+xx,down*3+xx,num+1,xx); tag/=4; return; } for(i=0;i<4;i++) { xx=a[map[r][num][i]]; rr=a[map[r][num][(i+1)%4]]; yy=a[map[r][num][(i+2)%4]]; ll=a[map[r][num][(i+3)%4]]; if(right==-1 || ll==right) DFS(r,up*3+xx,down*3+yy,num+1,rr); } } int main() { int i,j,ncase,t; scanf("%d",&ncase); a['F']=0; a['C']=1; a['R']=2; s[0]=1; for(i=1;i<=12;i++) s[i]=s[i-1]*3; for(t=1;t<=ncase;t++) { scanf("%d%d",&n,&m); for(i=0;i<n;i++) for(j=0;j<m;j++) scanf("%s",map[i][j]); flag=0; memset(dp,0,sizeof(dp)); for(i=0;i<n;i++) { tag=1; flag=(flag+1)%2; DFS(i,0,0,0,-1); for(j=0;j<s[m];j++) dp[(flag+1)%2][j]=0; } sum=0; for(i=0;i<s[m];i++) { sum+=dp[flag][i]; sum%=mod; } printf("Case %d: %I64d\n",t,sum); } return 0; }