这里的几个判断是通过下面这个博客,搞懂了轮廓线的定义以及状态转移的:
https://www.cnblogs.com/iiyiyi/p/5846864.html
不过,这个图的轮廓线应该是这样的:
我们当前需要做出来的决策是点(i,j),之前的1代表之前的状态已经确定好(否则是不合法的)
红色线标注出来的是轮廓线,蓝色线标注的是二进制的ID号,是从上到下,从左到右,从大到小标号的
所以,我们当前(i,j)格子有两种方案:
A:不摆~
B:摆,想摆一定是有条件的,同时满足四个条件
条件1:左上角没有摆:左上角存在,且没有摆
条件2:上面没有摆:上面存在,且没有摆
条件3:右上角没有摆:右上角存在,且没有摆
条件4:左面没有摆:左面存在,且没有摆
存在:用(i,j)坐标来判断
是否摆:看当前状态k的对应的二进制位是否为1~~~
(所以,看懂很简单,那为啥不压缩了就挂了。。。)
AC代码:
#include <cstdio>
#include <cstring>
using namespace std;
const int maxn = 10;
int n,K;
long long dp[2][1<<maxn][100],ans;
int getnext(int k){
if (k & (1<<n))
k -= 1<<n;
return k<<1;
}
/*
i:0->n-1
j:0->n-1
*/
bool check(int i,int j,int k){
if (i&&j&&(k&(1<<n))) return false;//左上角
// 在第一行或者在第一列或者左上角没有国王
if (i&&(k&(1<<(n-1)))) return false;//上
// 在第一行或者上面没有国王
if (i&&(j<n-1)&&(k&(1<<(n-2)))) return false;//右上角
//在最后一列或者在第一行或者右上角没有国王
if (j&&(k&1)) return false;//左边
// 在第一列或者左边没有国王
return true;
}
int main(){
//freopen("input.txt","r",stdin);
scanf("%d%d",&n,&K);
int cur=0;
dp[0][0][0]=1;
for(int i=0;i<n;i++)
for(int j=0;j<n;j++){
cur ^= 1;
memset(dp[cur],0,sizeof(dp[cur]));
for(int k=0;k<(1<<(n+1));k++)
for(int t=0;t<=K;t++){
//int now=getnext(k);
int now=(k<<1)%(1<<(n+1));
dp[cur][now][t]+=dp[cur^1][k][t];
if (t<K&&check(i,j,k)) dp[cur][now+1][t+1]+=dp[cur^1][k][t];
}
}
ans=0;
for(int k=0;k<(1<<(n+1));k++)
ans+=dp[cur][k][K];
printf("%lld\n",ans);
return 0;
}
改成底下这样就不知道为啥会wa了,很尴尬
#include <cstdio>
#include <cstring>
using namespace std;
const int maxn = 10;
int n,K;
long long dp[maxn][maxn][1<<maxn][100],ans;
int getnext(int k){
if (k & (1<<n))
k -= 1<<n;
return k<<1;
}
/*
i:0->n-1
j:0->n-1
bool check(int i,int j,int k){
if (i&&j&&(k&(1<<n))) return false;//左上角
// 在第一行或者在第一列或者左上角没有国王
if (i&&(k&(1<<(n-1)))) return false;//上
// 在第一行或者上面没有国王
if (i&&(j<n-1)&&(k&(1<<(n-2)))) return false;//右上角
//在最后一列或者在第一行或者右上角没有国王
if (j&&(k&1)) return false;//左边
// 在第一列或者左边没有国王
return true;
}*/
//i:1->n
//j:1->n
bool check(int i,int j,int s){
if (i>1&&j>1&&(s&(1<<n))) return 0;
if (i>1&&(s&(1<<n-1))) return 0;
if (i>1&&j<n&&(s&(1<<n-2))) return 0;
if (j>1&&(s&1)) return 0;
return 1;
}
int main(){
scanf("%d%d",&n,&K);
memset(dp,0,sizeof(dp));
dp[0][n][0][0]=1;
for(int i=1;i<=n;i++){
for(int j=0;j<(1<<n);j++)
for(int k=0;k<=K;k++)
dp[i][0][j<<1][k]=dp[i-1][n][j][k];
for(int j=1;j<=n;j++)
for(int k=0;k<(1<<(n+1));k++)
for(int t=0;t<=K;t++){
int now=getnext(k);
//int now=(k<<1)%(1<<(n+1));
dp[i][j][now][t]+=dp[i][j-1][k][t];
if (t<K&&check(i,j,k)) dp[i][j][now+1][t+1]+=dp[i][j-1][k][t];
}
}
ans=0;
for(int k=0;k<(1<<(n+1));k++)
ans+=dp[n][n][k][K];
printf("%lld\n",ans);
return 0;
}