Loading

AcWing 1064. 小国王

题目链接:

https://www.acwing.com/problem/content/1066/

题解:

需要分析出来,第j+1列的摆放,只和第j列的摆放有关系,这很重要,本质上和蒙德里安那题是一致的,只是合法状态的转移计算更加复杂,需要预处理的地方更多。

AC代码:

// f[i][j][k]: 前i-1列已经摆好,且已经使用了j个国王,第i列为状态k的所有合法方案的数量
// 状态a -> 状态b为合法,a和b都不能有相邻的1,且(a & b) == 0 && (a | b)不能有相邻的1

import java.util.*;

public class Main {
    static int N = 12, M = 110, K = 1 << 10;
    static long[][][] f = new long[N][M][K];
    static Map<Integer, List<Integer>> h = new HashMap<>();
    static List<Integer> st = new ArrayList<>();
    static int[] cnt = new int[K];
    static int n, m;
    
    // 判断st是否合法
    static boolean check(int st) {
        return (st & st >> 1) == 0;
    }
    

    static int count(int st) {
        int res = 0;
        for (int i = 0; i < n; i ++) {
            if ((st >> i & 1) == 1) res ++;
        }
        
        return res;
    }
    
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        n = sc.nextInt();
        m = sc.nextInt();
        
        for (int i = 0; i < (1 << n); i ++) {
            if (check(i)) {
                st.add(i);
                cnt[i] = count(i);
            }
        }
        
        for (int i = 0; i < st.size(); i ++) {
            for (int j = 0; j < st.size(); j ++) {
                int a = st.get(i), b = st.get(j);
                if ((a & b) == 0 && check(a | b)) {
                    List<Integer> list = h.getOrDefault(i, new ArrayList<>());
                    list.add(j);
                    h.put(i, list);
                }
            }
        }
        
        
        f[0][0][0] = 1;
        for (int i = 1; i <= n + 1; i ++) 
            for (int j = 0; j <= m; j ++) 
                for (int u = 0; u < st.size(); u ++)
                    if (h.containsKey(u))
                        for (Integer v : h.get(u)) {
                            int a = st.get(u), b = st.get(v);
                            // 为什么不加上cnt[b] <= j - cnt[a]也是对的?
                            // 因为,状态集合只规定了算,合法方案,这种非合法方案数量的状态表示为0,加上也不会错
                            if (j - cnt[a] >= 0) {
                                f[i][j][u] += f[i - 1][j - cnt[a]][v];
                            }
                        }
                    
        System.out.println(f[n + 1][m][0]);
        
    }
}
posted @ 2022-05-11 15:16  Doubest  阅读(20)  评论(0编辑  收藏  举报