一文读懂不同状态的动态规划

最近做笔试题,发现各个公司特喜欢出这种包含不同状态选择的动态规划,不同的选择会对接下来的结果有所限制和影响。于是对这些题总结了一个通用套路。
有多少种状态就设多长的数组
比如有两种状态,设dp[n][2],分别存每个状态对应的结果,接下来的选择要用到哪个状态就选哪个。如果不能get到,且看下面的题目和解释。

上三道笔试题来品品

网易2020校招笔试题-跳柱子
小易有n根柱子,第n根柱子的高度为。一开始小易站在第一根柱子上。小易能从第i根柱子跳到第j根柱子,当且仅当hj<=hi且1<=j-i<=k。其中k为指定的一个数字。
另外小易拥有一次释放超能力的机会。这个超能力能让小易从柱子i跳到任意满足1<=j-i<=k的柱子而无视柱子j高度的限制。
现在小易想知道,小易是否能到达第n根柱子。
题目理解:能跳跃的要求仅是hj<=hi,至于i和j之间是否有柱子大于hi并无影响

这种类型其实是蛮常见的动态规划,就是前面可能改变一个状态,导致原本的递推公式不能用,这时候可以将一维的状态转移方程变成二维的,用来存储多出来的状态。
类似的题目还有买卖有冷冻期的股票等。

import java.util.*;
public class Main{
    public static void main(String []args){
        Scanner in=new Scanner(System.in);
        int op=in.nextInt();
        while(op-->0)
        {
            int n=in.nextInt(),k=in.nextInt();
            long []num=new long[n];
            for(int i=0;i<n;i++)
            {
                num[i]=in.nextLong();
            }
            boolean [][]jump=new boolean[n][2];//记录每个柱子能否到达
            jump[0][0]=true;//表示没有使用超能力
            jump[0][1]=true;//表示使用超能力
            for(int i=0;i<n;i++)
            {
                for(int j=1;j<=k&&j+i<n;j++)
                {
                    if(num[j+i]<=num[i])//可以通过普通跳跃到达
                    {//更新状态跟出发柱子相同
                        jump[j+i][0]|=jump[i][0];//没有使用超能力两者都要更新
                        jump[j+i][1]|=jump[i][1];
                    }
                    else {
                        jump[j+i][1]|=jump[i][0];//使用了超能力只更新[j+i][1],这个值只能从没使用超能力的状态到达
                        //该位置没使用超能力的情况仍是不能到达,其他状态不能从这个位置下再使用超能力(或者说不可达)
                    }
                }
                 
            }
            if(jump[n-1][0]||jump[n-1][1])
                    System.out.println("YES");
                else System.out.println("NO");
        }
    }
}

携程股票价格

一个一维数组,记录n天中每天的携程股价。
股市交易规则如下:a)一天只能有买进或者卖出一种操作,也可以不做任何操作,卖出时价格减买入时价格即为收益b)每次卖出操作后有冻结期,k天之后才能进行下一次买进操作(k>=1)c)买进之后必须卖出才能再次买进设计一个算法,找到交易收益最大化的买进卖出策略,返回最后的最大收益值

import java.util.*;
public class Main{
	public static void main(String[]args){
    	Scanner in=new Scanner(System.in);
        int len=in.nextInt();
        int []prices=new int[len];
        for(int i=0;i<len;i++)
                {
                	prices[i]=in.nextInt();
                }
                int k=in.nextInt();
       
	        int [][]dp=new int[len][2];
	        dp[0][0]=0;
	        dp[0][1]=-prices[0];
	        for(int i=1;i<=k;i++)
	        {
	        	dp[i][0]=Math.max(dp[i-1][0], dp[i-1][1]+prices[i]);
		        dp[i][1]=Math.max(dp[i-1][1], dp[0][0]-prices[i]);
	        }
	       
	        for(int i=k+1;i<len;i++)
	        {
	    dp[i][0]=Math.max(dp[i-1][1]+prices[i],dp[i-1][0]);
	    dp[i][1]=Math.max(dp[i-1][1],dp[i-k-1][0]-prices[i]);
	        }
            System.out.println(dp[len-1][0]);
    }
}

腾讯-假期

由于业绩优秀,公司给小Q放了 n 天的假,身为工作狂的小Q打算在在假期中工作、锻炼或者休息。他有个奇怪的习惯:不会连续两天工作或锻炼。只有当公司营业时,小Q才能去工作,只有当健身房营业时,小Q才能去健身,小Q一天只能干一件事。给出假期中公司,健身房的营业情况,求小Q最少需要休息几天。

输入描述:
第一行一个整数 n(1≤n≤100000)n(1\leq n\leq 100000)n(1≤n≤100000) 表示放假天数第二行 n 个数 每个数为0或1,第 i 个数表示公司在第 i 天是否营业第三行 n 个数 每个数为0或1,第 i 个数表示健身房在第 i 天是否营业(1为营业 0为不营业)
输出描述:
一个整数,表示小Q休息的最少天数
示例1
输入
4
1 1 0 0
0 1 1 0
输出
2

import java.util.*;
public class Main{
    public static void main(String[]args){
        Scanner in=new Scanner(System.in);
        int n=in.nextInt();
        int[]work=new int[n];
        int[]fit=new int[n];
        for(int i=0;i<n;i++)
            work[i]=in.nextInt();
        for(int i=0;i<n;i++)
            fit[i]=in.nextInt();
        int [][]dp=new int[n][2];
        dp[0][0]=work[0];
        dp[0][1]=fit[0];
        for(int i=0;i<n-1;i++)
        {
            if(work[i]==0)
                dp[i+1][0]=work[i+1]+Math.max(dp[i][0],dp[i][1]);
            else dp[i+1][0]=work[i+1]+dp[i][1];
            if(fit[i]!=0)
                dp[i+1][1]=fit[i+1]+dp[i][0];
            else dp[i+1][1]=Math.max(dp[i][0],dp[i][1])+fit[i+1];
        }
        int max=Math.max(dp[n-1][0],dp[n-1][1]);
        System.out.print(n-max);
    }
}
发布了45 篇原创文章 · 获赞 4 · 访问量 1031

猜你喜欢

转载自blog.csdn.net/weixin_43838915/article/details/105339998
今日推荐