这道题也是一道状压DP。
http://www.cnblogs.com/Ronald-MOK1426/p/8456798.html
这个博客写的比较详细。
其实入门了第一道状压DP:https://blog.csdn.net/King8611/article/details/82771818后这道题还是挺容易的。
不过dp加了个关系。
dp[i][j][k]表示第i个状态为j的情况下,当前摆放到这一层棋数为k的情况
然后其他和之前的大同小异:
import java.util.*;
import java.io.*;
public class Main {
static int state[],stateLen; //表示所有可能状态,长度
static int num[]; //表示每种状态下可能拥有的个数
static long dp[][][]; //dp[i][j][k]表示第i个状态为j的情况下,当前摆放到这一层棋数为k的情况`
static int n,m;
static StreamTokenizer in=new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
public static void main(String[] args) throws Exception {
init();
setState();
setDp();
System.out.println(getAns());
}
static void init() throws Exception{
n=getInt();
m=getInt();
}
static void setState() {
state=new int[1000];
num=new int[1000];
int totle=1<<n;
for(int i=0;i<totle;i++)
if(isOk(i)) {
state[stateLen++]=i;
for(int j=i;j!=0;j=j>>1)
num[stateLen-1]+=j&1;
}
}
static void setDp() {
dp=new long [15][1000][100];
for(int i=0;i<stateLen;i++)
dp[0][i][num[i]]++;
//循环计算dp,我也不知道为啥居然不超时
for(int i=1;i<n;i++) {
for(int j=0;j<stateLen;j++) {
for(int k=0;k<stateLen;k++) {
if(isOk(j,k)) {
for(int l=0;l<=m;l++) {
if(num[j]+l<=m)
dp[i][j][num[j]+l]+=dp[i-1][k][l];
}
}
}
}
}
}
static long getAns() {
long ans=0;
for(int i=0;i<stateLen;i++)
ans+=dp[n-1][i][m];
return ans;
}
//判断这层是否和上一层冲突
static boolean isOk(int i,int j) {
int a=state[i],b=state[j];
return ((b&a)==0)&&(((b<<1)&a)==0)&&((b>>1&a)==0);
}
//判断这一层是否和这一层冲突
static boolean isOk(int x) {
return (x&(x<<1))==0;
}
static int getInt() throws Exception{
in.nextToken();
return (int) in.nval;
}
}