(“白话文”详解)蓝桥杯模拟 摆动序列

题目信息:
  在网上看到了许多题解,但好多人好像没有明白奇、偶状态转移方程怎么推导出来了,这是一道比较好的动态规划的题目,如果你找到现在也没有搞懂状态转移方程的由来,那么恭喜你这篇文章是个突破,看完这篇题目你就可以懂了!!!
  (为了更好的理解,看这道题目之前,你可以先做一道初级的摆动序列的问题:链接: 动态规划详解——(初级)摆动序列.)

问题描述
如果一个序列的奇数项都比前一项大,偶数项都比前一项小,则称为一个摆动序列。即 a[2i]a[2i]。
  小明想知道,长度为 m,每个数都是 1 到 n 之间的正整数的摆动序列一共有多少个。

输入格式
输入一行包含两个整数 m,n。

输出格式
输出一个整数,表示答案。答案可能很大,请输出答案除以10000的余数。

样例输入
3 4

样例输出
14

样例说明
以下是符合要求的摆动序列:
  2 1 2
  2 1 3
  2 1 4
  3 1 2
  3 1 3
  3 1 4
  3 2 3
  3 2 4
  4 1 2
  4 1 3
  4 1 4
  4 2 3
  4 2 4
  4 3 4

评测用例规模与约定
对于 20% 的评测用例,1 <= n, m <= 5;
  对于 50% 的评测用例,1 <= n, m <= 10;
  对于 80% 的评测用例,1 <= n, m <= 100;
  对于所有评测用例,1 <= n, m <= 1000。
  

动态规划分析:

  • 状态分析:在这道题目中,数字在奇、偶位置不同所符合的条件不同,简而言之:奇数位置的数字要比前一位元素大、偶数位置的数字要比前一位小;这造就了状态转移方程的不同

  • 状态: dp[i][j]状态数组表示:长度为j ,即j位置上放 以i数字为**基准(基准一词非常重要)** 满足条件的序列数目 有多少个(这句话非常重要)

    • (eg:假设j为奇数 ,长度为j的序列,则在j位置 上放i数字 满足条件,则在j位置 上放数字i+1 也满足条件,因为数字i 都大于前面一位的数字了,数字i+1 也一定大于前面的数字,所以满足条件)
    • (同理,eg:假设j为偶数 ,长度为j的序列,则在j位置 上放i数字 满足条件,则在j位置 上放数字i-1 也满足条件,因为数字i 小于前面一位的数字了,数字i-1 也一定小于前面的数字,所以满足条件)
  • 状态转移方程:

    • j位置为奇数: 当求dp[i][j]时,即长度为j,以i为基准其来源有两部分:dp[i+1][j](j位置放比i大的值)、dp[i-1][j-1](j位置i,即j-1位要比i小)
      简而言之——长度为j,大于等于i的选择方案总数
    • j位置为偶数: 当求dp[i][j]时,即长度为j,以i为基准其来源有两部分:dp[i-1][j](j位置放比i小的值)、dp[i+1][j-1](j位置i,即j-1位要比i大)
      简而言之——长度为j,小于等于i的选择方案总数
  • 初始状态:i
    j为1时,即序列长度为1,那么其一定是满足条件的序列,第一项是奇数项,dp[i][1]=n-i+1; 大于等于j的选择方案总数

  • 输出:
    当m为奇数时,结合前面分析最后一位应当放最小值,即dp[1][m]
    当m为偶数时,结合前面分析最后一位应当放最最大值值,即dp[n][m]

AC代码(java):

package 蓝桥杯模拟_摆动序列;
import java.util.*;

public class Main {
	public static void main(String[] args) {
		Scanner sc=new Scanner(System.in);
		int m=sc.nextInt();
		int n=sc.nextInt();
		
		int[][] dp=new int[n+5][m+5];	//状态数组,长度为j,即j位置上放以i为基础满足条件的序列的数目有多少个
		
		for(int i=1;i<=n;i++) {//初始化
			dp[i][1]=n-i+1;		//1为奇数位置
		}
		
		for(int j=2;j<=m;j++) {
			if(j%2==0) {
				for(int i=1;i<=n;i++) {
					dp[i][j]=(dp[i+1][j-1]+dp[i-1][j])%10000;	//以所放数字i为基础,考虑满足条件的序列
				}
			}
			else {
				for(int i=n;i>=1;i--) {
					dp[i][j]=(dp[i+1][j]+dp[i-1][j-1])%10000;	//以所放数字i为基础,考虑满足条件的序列
				}
			}
		}
		
		//判断调价输出
		if(m%2==0) {
			System.out.println(dp[n][m]);
		}
		else {
			System.out.println(dp[1][m]);
		}
		
	}
}

你可能感兴趣的:(SF_C++/Java,动态规划,算法,java)