Java实现蓝桥杯 垒骰子---dp动态规划+矩阵快速幂

赌圣atm晚年迷恋上了垒骰子,就是把骰子一个垒在另一个上边,不能歪歪扭扭,要垒成方柱体。
  经过长期观察,atm 发现了稳定骰子的奥秘:有些数字的面贴着会互相排斥!
  我们先来规范一下骰子:1 的对面是 4,2 的对面是 5,3 的对面是 6。
  假设有 m 组互斥现象,每组中的那两个数字的面紧贴在一起,骰子就不能稳定的垒起来。
  atm想计算一下有多少种不同的可能的垒骰子方式。
  两种垒骰子方式相同,当且仅当这两种方式中对应高度的骰子的对应数字的朝向都相同。
  由于方案数可能过多,请输出模 10^9 + 7 的结果。

  不要小看了 atm 的骰子数量哦~

  「输入格式」
  第一行两个整数 n m
  n表示骰子数目
  接下来 m 行,每行两个整数 a b ,表示 a 和 b 数字不能紧贴在一起。

  「输出格式」
  一行一个数,表示答案模 10^9 + 7 的结果。

  「样例输入」
  2 1
  1 2

  「样例输出」
  544

  「数据范围」
  对于 30% 的数据:n <= 5
  对于 60% 的数据:n <= 100
  对于 100% 的数据:0 < n <= 10^9, m <= 36


  资源约定:
  峰值内存消耗 < 256M
  CPU消耗 < 2000ms


  请严格按要求输出,不要画蛇添足地打印类似:“请您输入...” 的多余内容。

  所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。

  注意: main函数需要返回0
  注意: 只使用ANSI C/ANSI C++ 标准,不要调用依赖于编译环境或操作系统的特殊函数。
  注意: 所有依赖的函数必须明确地在源文件中 #include , 不能通过工程设置而省略常用头文件。

  提交时,注意选择所期望的编译器类型。

1.dp数组实现

这种方法只能过8个测试点,因为超时,注意各个数组下标的含义和起始位置。




import java.sql.Array;
import java.util.*;
import java.awt.print.Printable;
import java.lang.*;

public class test2 {

    /**
     * 矛盾数组,从下标1开始使用,如果矛盾则为-1,否则为1
     */
    static int[][] md; // 矛盾数组
    /**
     * dp[i][j]数组的含义是第i个骰子时,j面朝下的的骰子摆法有多少种,此时不包括转向的情况
     */
    static long[][] dp; // dp数组
    /**
     * 骰子的点数的对立面,下标为0不使用
     */
    static int[] xd = new int[7]; // 存储的骰子的相对面
    static int mod = 1000000000 + 7;
    static long C=4;
    public static void main(String[] arge) {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();// 色子
        int m = scanner.nextInt();// 冲突对
        xd = new int[]{0, 4, 5, 6, 1, 2, 3};
        md = new int[7][7];
        //将md数组(存储冲突数字)
        for (int i = 0; i < 7; i++) {
            for (int j = 0; j < md.length; j++) {
                md[i][j] = -1;
            }
        }
       /*
       md数组初始化
        */
        for (int i = 0; i < m; i++) {
            int x = scanner.nextInt();
            int y = scanner.nextInt();
            md[x][y] = 1;
            md[y][x] = 1;
        }

        /*
        dp数组初始化
         */
        dp = new long[n][8];
        for (int i = 1; i < 7 + 1; i++) {
            dp[0][i] = 1;
        }

        /*
        开始dp,因为骰子可以转向,所以用C记录到第i个色子时,转向方式有多少种
         */
        for (int i = 1; i < n; i++) {
            C = C * 4 % mod;
            for (int j = 1; j < 7; j++) {
                dp[i][j] = getSum(i, j);
            }
        }
        long sum = 0;
        for (int i = 1; i < 7; i++) {
            sum = (sum + (dp[n-1][i] * C)) % mod;
        }
        System.out.print(sum);
    }

    /*
     * j:是朝下的那个点数
     *获得dp[i][j]应该存储的数字,根据dp[i-1]计算dp[i][j]
     * */
    public static long getSum(int i, int j) {
        int sum = 0;
        for (int k = 1; k < 7; k++) {
            if (md[j][xd[k]] != -1) {
                continue;
            }
            sum += dp[i - 1][k];
            sum=sum%mod;
        }
        return sum%mod;
    }
}

2.矩阵快速幂

import java.sql.Array;
import java.util.*;
import java.awt.print.Printable;
import java.lang.*;


class Main2 {
    static Matrixm conflict = new Matrixm(6, 6);

    static int[] xd = new int[7];
    static int mod = 1000000000 + 7;
    static long C = 4;


    public static void main(String[] arge) {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();// 色子数
        int m = scanner.nextInt();// 冲突对
        xd = new int[]{0, 4, 5, 6, 1, 2, 3};

        // 冲突数组初始化
        for (int i = 0; i < conflict.m; i++) {
            for (int j = 0; j < conflict.n; j++) {
                conflict.arr[i][j] = 4;
            }
        }

        for (int i = 0; i < m; i++) {
            int x = scanner.nextInt();
            int y = scanner.nextInt();
            conflict.arr[x - 1][xd[y] - 1] = 0;
            conflict.arr[y - 1][xd[x] - 1] = 0;
        }

        conflict = get_power(conflict, n - 1);// 矩阵的n-1个幂×

        long sum = 0;

        for (int hang = 0; hang < conflict.m; hang++) {
            long temp = 0;
            for (int lie = 0; lie < conflict.n; lie++) {
                temp += 4 * conflict.arr[hang][lie];
                temp = temp % mod;
            }
            sum += temp;
            sum = sum % mod;

        }

        System.out.println(sum);

    }


    /**
     * 矩阵的快速幂
     *
     * @param matrixm :服务的矩阵
     * @param n       :幂
     * @return :结果
     */
    public static Matrixm get_power(Matrixm matrixm, int n) {
        Matrixm unit = new Matrixm(6, 6);//获得一个单位矩阵
        get_identity_martix(unit, 1);
        while (n != 0) {
            if ((n & 1) != 0) {// 如果这是 n的二进制串不是0,既是1,则将unit与A相乘
                unit = get_matrix_multi(unit, matrixm);
            }
            matrixm = get_matrix_multi(matrixm, matrixm);
            n = n >> 1;
        }
        return unit;
    }

    public static Matrixm get_matrix_multi(Matrixm A, Matrixm B) {
        Matrixm temp = new Matrixm(A.m, B.n); // 结果矩阵

        for (int hang = 0; hang < A.m; hang++) { // A矩阵的行
            for (int lie = 0; lie < B.n; lie++) { // B矩阵的列
                long res = 0;
                for (int index = 0; index < A.n; index++) {// 进行相×相加
                    res += (A.arr[hang][index] * B.arr[index][lie]) % mod;
                    res = res % mod;
                }
                temp.arr[hang][lie] = res;
                temp.arr[hang][lie] = temp.arr[hang][lie] % mod;
            }
        }
        return temp;
    }

    /**
     * @param x 单位矩阵的中心线的数字
     * @return :一个单位矩阵
     */
    public static Matrixm get_identity_martix(Matrixm matrixm, int x) {
        //Matrixm unity = new Matrixm(6, 6);
        for (int i = 0; i < 6; i++) {
            for (int j = 0; j < 6; j++) {
                if (i == j) {
                    matrixm.arr[i][j] = x;
                    continue;
                }
                matrixm.arr[i][j] = 0;
            }
        }
        return matrixm;
    }
}


class Matrixm {
    int m;// 行
    int n;// 列

    long[][] arr = new long[6][6];

    public Matrixm(int m, int n) {
        this.m = m;
        this.n = n;
    }
}

你可能感兴趣的:(蓝桥杯,职场和发展,java,动态规划)