hdu4064 三进制状态压缩 好题!

时间:2021-06-21 14:15:26

还不太会做这类题,总之感觉有点难啊。

用深搜代替打表求出一行所有的可行状态,注意要进行剪枝

这是自己理解的代码,但是tle了

#include<bits/stdc++.h>
using namespace std;
#define mod 1000000007
#define maxn 600005
int n,m,dp[][maxn],sum;
char mp[][][];
int a[],tag,flag,s[];
//
void dfs(int r,int num,int up,int down,int right){//用dfs搜索出第r行的下状态,上状态 和右侧颜色
int xx,rr,yy,ll,i;
if(num==m){//搜满了一行
if(r==)dp[flag][down]+=tag;//如果是第一行,那么只要把组成这种状态的方案数加上即可
else {
dp[flag][down]+=dp[(flag+)%][up]*tag;//加上上一行下状态为up的计数值
dp[flag][down]%=mod;
}
return;
}
for(int i=;i<;i++)//判断改行第i个方块是不是四方相同的
if(mp[r][num][i]!=mp[r][num][])break;
if(i==){//四方相同的块直接跳过即可,并且这一行的结果要加上4
tag*=;
xx=a[mp[r][num][]];
if(xx==right || right==-)dfs(r,num+,up*+xx,down*+xx,xx);
tag/=;
return;
} for(int i=;i<;i++){//枚举该方块的安放方式,符合条件的进入下一轮深搜
xx=a[mp[r][num][i]];//下一格上方
rr=a[mp[r][num][(i+)%]];//下一格右侧
yy=a[mp[r][num][(i+)%]];//下一格下放
ll=a[mp[r][num][(i+)%]];//下一格左侧
if(right==- || ll==right)//如果是第一格或者左侧对上这一格的右侧,就可以往下搜了
dfs(r,num+,up*+xx,down*+yy,rr);
}
} int ncase,t;
void init(){
cin>>ncase;a['F']=,a['C']=,a['R']=;
s[]=;
for(int i=;i<=;i++)s[i]=s[i-]*;//使用三进制
flag=;
memset(dp,,sizeof dp);
} int main(){
init();
for(int t=;t<=ncase;t++){
cin>>n>>m;
for(int i=;i<n;i++)
for(int j=;j<m;j++)
cin>>mp[i][j]; for(int i=;i<n;i++){//利用滚动数组,dp[flag][s]表示第i行状态s下的方案数
tag=;flag^=;
memset(dp[flag],,sizeof dp[flag]);
dfs(i,,,,-);
} sum=;
for(int i=;i<s[m];i++)//求和
sum+=dp[flag][i],sum%=mod; printf("Case %d: %lld\n",t,sum);
}
}