版权声明:转载注明出处,部分带(坑)文章谢绝转载。 https://blog.csdn.net/linjiayang2016/article/details/83864363
题意
给出
的矩阵,选出若干个
变成
,使得没有两个
有公共边,求方案数量。
数据范围
题解
看到这么小的数据范围,显然可以状态压缩,考虑状压缩DP。
设
表示考虑前
行且第
行状态为
(压缩)的方案数量。
枚举
表示上一行的状态(压缩),则有:
最后的答案为
,时间复杂度
代码
#include <bits/stdc++.h>
using namespace std;
#define mod 100000000
int m, n, f[15][4100], F[15], field[15][15];
bool check[4100];//只考虑本行是否合法
int main() {
scanf("%d%d",&m,&n);
for (int i=1;i<=m;i++)
for (int j=1;j<=n;j++)
scanf("%d",&field[i][j]);
for (int i=1;i<=m;i++)//压缩行
for (int j=1;j<=n;j++)
F[i]=(F[i]<<1)+field[i][j];
for (int i=0;i<(1<<n);i++)
check[i]=((i&(i<<1))==0) && ((i&(i>>1))==0);
f[0][0]=1;
for(int i=1;i<=m;i++)
for(int j=0;j<(1<<n);j++)
if(check[j] && ((j&F[i])==j))
for(int k=0;k<(1<<n);k++)
if((k & j)==0)
f[i][j]=(f[i][j]+f[i-1][k])%mod;
int ans=0;
for(int i=0;i<(1<<n);i++)
ans+=f[m][i],ans%=mod;
printf("%d",ans);
return 0;
}
上面的方法能很快地通过本题,但根据本题的数据范围,计算次数约为两亿次左右,有些玄学,因此我们需要更高效的算法。考虑更换方程定义。
设
表示考虑到
行
列的格子,此时的轮廓线状态为
(压缩)。
例如:下表
处表示状态
这个定义依然很好转移,处理好边界即可,而且可以用滚动数组优化掉前两维。
最后的答案是
,这个算法的时间复杂度为
,运算量约为六十万次,能轻易AC。
代码
#include<bits/stdc++.h>
using namespace std;
#define mod 100000000
#define maxn 13
int n,m,a[maxn][maxn];
int f[2][1<<maxn],cur;
int main(void){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
scanf("%d",&a[i][j]);
f[0][0]=1;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++){
memset(f[cur^=1],0,sizeof f[cur]);
for(int k=0;k<(1<<m);k++){
int up=(k&(1<<(j-1))),left=0;//拆出上面和左边的位置
if(j>1) left=(k&(1<<(j-2)));
if(i==1&&up!=0) continue;//第一行的上面不可能被选择
if(j==1&&left!=0) continue;//第一列的左边不可能被选择
if(left&&up)//左边和上面都选了,只能不选
f[cur][k^(1<<j-1)]=(f[cur][k^(1<<j-1)]+f[cur^1][k])%mod;
else if(up)//上面选了,只能不选
f[cur][k^(1<<j-1)]=(f[cur][k^(1<<j-1)]+f[cur^1][k])%mod;
else if(left)//左边选了,只能不选
f[cur][k]=(f[cur][k]+f[cur^1][k])%mod;
else if(a[i][j]==0)//不为0,只能不选
f[cur][k]=(f[cur][k]+f[cur^1][k])%mod;
else{
f[cur][k]=(f[cur][k]+f[cur^1][k])%mod;//选
f[cur][k^(1<<j-1)]=(f[cur][k^(1<<j-1)]+f[cur^1][k])%mod;//不选
}
}
}
int ans=0;
for(int i=0;i<(1<<m);i++)//统计答案
ans=(ans+f[cur][i])%mod;
printf("%d",ans);
return 0;
}