这道题我作为初学者来看有些懵。。
上网搜了一下发现大神都说是状态压缩。。
所以就开始学了一下状态压缩
状态压缩就是把每一行的状态转化为2进制,0表示不填,1表示填,只问合法状态,不用把每一个状态都问一遍。。
对时间和空间都很节省。。
这道题的dp方程也不难想(只要你会状压)。。
学会了状压之后很快就做出来了。。这道题还是比较入门。。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<sstream>
using namespace std;
long long f[11][(1<<11)+10][90]; //f[i][j][k]表示第i行填j状态,填完之后前i行有k个king
long long a[16][16],v[(1<<9)+10],vn;
long long t[610];
char s[110000];int n;
int main() {
//freopen("king.in","r",stdin);freopen("king.out","w",stdout);
for(int i=1;i<=600;i++) { //t数组表示每一个状态有多少个1
int xx=i,m=0;
while(xx!=0) {
if(xx%2==1)
m++;
xx/=2;
}
t[i]=m;
}
int k;
scanf("%d%d",&n,&k);
memset(f,0,sizeof(f));
int mmax=(1<<n)-1;
for(int x=0;x<=mmax;x++) { //存有用的状态
if(((x<<1)&x)==0) {
f[1][x][t[x]]=1;
v[++vn]=x;
}
}
for(int i=2;i<=n+1;i++)
for(int p=1;p<=vn;p++) {
for(int q=1;q<=vn;q++)
if((v[p]&v[q])==0&&((v[p]>>1)&v[q])==0&&((v[p]<<1)&v[q])==0) //状态是否合法
for(int ii=k;ii>=t[v[p]];ii--)
f[i][v[p]][ii]=f[i][v[p]][ii]+f[i-1][v[q]][ii-t[v[p]]]; //dp方程
}
printf("%lld\n",f[n+1][0][k]); //n+1行不填表示了前n行所有的状态
return 0;
}