• 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]);
            
        }
    }
    
  • 相关阅读:
    Java面试——从JVM角度比较equals和==的区别
    Java线程和多线程(三)——线程安全和同步
    玩转Android之MVVM开发模式实战,炫酷的DataBinding!
    写点什么好呢2? 钱、事业、婚姻、人生意义
    写点什么好呢2? 钱、事业、婚姻、人生意义
    大型网站架构技术一览
    【树莓派】GSM900模块
    【Latex】数学公式排版
    【MYSQL】导入中文后乱码问题
    【R】shiny界面
  • 原文地址:https://www.cnblogs.com/doubest/p/16258045.html
Copyright © 2020-2023  润新知