文章目录
- 状压dp
- 小国王
- 玉米田
- 炮兵阵地
状压dp
小国王
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
public class Main{
static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
static PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
static int n = 0, k = 0; //棋盘行数 国王个数
static int cnt = 0; //同一行的合法状态个数
static int[] s = new int[1 << 12]; //同一行的合法状态集
static int[] num = new int[1 << 12]; //每个合法状态包含的国王数
static long[][][] dp = new long[12][144][1 << 12]; //前i行放了j个国王,第i行第a个状态时的方案数
public static void main(String[] args) throws IOException {
String[] nk = br.readLine().split(" ");
n = Integer.parseInt(nk[0]);
k = Integer.parseInt(nk[1]);
//预处理
for(int i = 0; i < (1 << n); i++) {
if((i & i >> 1) == 0) { //不存在相邻的1
s[cnt++] = i; //保存此合法状态
for(int j = 0; j < n; j++) {
num[i] += (i>>j&1); //统计每个合法状态包含1(国王)的个数
}
}
}
// System.out.println(cnt);
// for(int i = 0; i < cnt; i++) {
// System.out.println(Integer.toBinaryString(s[i]) + " " +num[s[i]]);
// }
//DP
dp[0][0][0] = 1; //不放国王也是一种状态
for(int i = 1; i <= n + 1; i++) {//枚举行
for(int j = 0; j <= k; j++) { //枚举国王数
//枚举国王数
for(int a = 0; a < cnt; a++) { //枚举第i行合法状态
for(int b = 0; b < cnt; b++) {
int c = num[s[a]]; //第i行第a个状态的国王数
//可以继续放国王,不存在同列的1,不存在斜对角的1
if((j >= c) && ((s[b] & s[a]) == 0) && ((s[b] & (s[a] << 1)) == 0) && ((s[b]&(s[a]>>1)) == 0)) {
dp[i][j][a] += dp[i-1][j-c][b];
}
}
}
}
}
System.out.println(dp[n+1][k][0]);
}
}
玉米田
✍
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
public class Main{
static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
static PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
static int mod = (int) 1e9;
static int n = 0, m = 0; //
static int[][] a = new int[15][15];
static int[] g = new int[15]; //各行土地的状态值
static int cnt = 0; //同一行的合法状态个数
static int[] s = new int[1 << 14]; //同一行的合法状态集
static long[][] dp = new long[15][1 << 15]; //种植了前i行,第i行第a个状态时的方案数
public static void main(String[] args) throws IOException {
String[] nm = br.readLine().split(" ");
n = Integer.parseInt(nm[0]);
m = Integer.parseInt(nm[1]);
//预处理
for(int i = 1;i <= n; i++) {
String[] aa = br.readLine().split(" ");
for(int j = 1; j <= m; j++) {
a[i][j] = Integer.parseInt(aa[j - 1]);
}
}
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= m; j++) {
int x = a[i][j];
g[i] = (g[i] << 1) + x;
}
// System.out.println(g[i]);
}
for(int i = 0; i < (1 << m); i++) {
if((i&i >> 1)==0) {
s[cnt++] = i;//保存一行的合法状态
}
}
dp[0][0] = 1;
for(int i = 1; i <= n + 1; i++) {
for(int a = 0; a < cnt; a++) { //第i行
for(int b = 0; b < cnt; b++) { //第i-1行状态
//a种在可以种的地方,a b没有相邻的1
if((s[a] & g[i]) == s[a] && (s[a] & s[b]) == 0) {
dp[i][a] = (dp[i][a] + dp[i-1][b])%mod;
}
}
}
}
//等价于只在1~n行种植
System.out.println(dp[n+1][0]);
}
}
炮兵阵地
✍