HDU 1024 Max Sum Plus Plus


DP问题


解题步骤已经在代码中解释的很清楚了


DP题的代码个人认为是挺难理解的,但是,如果理解了就会觉得很简单


需要注意一下的是,题目让分两段,必须就得分两段,即使分成两段之后的总和反而更小


比如代码注释中我举得例子


package 动态规划;

import java.util.Scanner;

public class _1024_选择多次最长子序列 {

	/**
	 * m=3,n=6      | -1 | 4 | -2 | 3 | -2 |  3  |
	 * 
	 * now:	   | 0  | -1 | 4 | 2  | 5 | 3  |  6  |
	 * 
	 * pre:    |-99 | -1 | 4 | 4  | 5 | 5  |  0  |
	 * 
	 * now:    | 0  | -1 | 3 | 2  | 7 | 5  |  8  |
	 * 
	 * pre:	   |-99 |-99 | 3 | 3  | 7 | 7  |  0  |
	 * 
	 * now:    | 0  | -1 | 3 | 1  | 6 | 5  |  10 |
	 * 
	 * pre:    |-99 |-99 |-99| 1  | 6 | 6  |  0  |
	 * 
	 * @param args
	 */

	// http://acm.hdu.edu.cn/showproblem.php?pid=1024
	// 状态: dp[i][j] --- 表示前j个数中的最大i段子段和,并且a[j]包涵于最后一个子段
	// 状态转移方程: dp[i][j]=max{dp[i][j-1]+A[j],dp[i-1][t]+a[j] (i-1<=t<n-m+i) }
	// 关于状态转移方程的解释:
	// dp[i][j]由两种情况得到,
	// 一、a[j]包涵于最后一个子段,这种情况的最大值就是EDP[i][j-1]+a[j];
	// 二、a[j]就是最后一个子段,这种情况的最大值是 dp[i-1][t]+a[j] (i-1<=t<=n-m+i) 中
	// 的最大值.
	// 以下用滚动数组进行DP
	// 在求 dp[i][j]时也顺便把 max{dp[i - 1][t]} ( i - 1 <= t < j) 求出来,这样的话
	// 时间复杂度仅为 O(N*(N - M + 1)) , 空间为 O( N )

	public static void main(String[] args) {

		Scanner sc = new Scanner(System.in);

		while (sc.hasNext()) {

			int m = sc.nextInt();
			int n = sc.nextInt();

			// 输入
			int[] num = new int[n + 1];

			// 滚动数组
			// now[j]代表在加上num[j]这个数之后最大可能的值,可能会更小
			int[] now = new int[n + 1];
			// pre[j]代表在num[j+1]这个数之前的最优值
			int[] pre = new int[n + 1];

			// 输入
			for (int i = 1; i <= n; i++) {

				num[i] = sc.nextInt();

			}

			// 初始化max_pre
			int max_pre = 0;

			// 遍历m次
			for (int i = 1; i <= m; i++) {

				// 刚开始max_pre值为整数型最小值
				max_pre = -Integer.MAX_VALUE;

				// 遍历i→n
				//这里j=i的意思是,前边i个数已经没得选了,因为必定得分段,即必须得选上
				//注意,now[j],j=i时,这个数也是不得不选的
				
				//从j开始,也是为了让pre[j-1]是负最大值,j=i+1时用得着
				//表示下一个i,第i+1个数之前没得选择,它前边只能是i个值相加
				//之后就有一定的选择性了
				
				//比如,运行程序,测试一下:
//				1 2 -1 4
//				4
//				2 2 -1 4
//				3
				//可见,第二次 两个都选上了,虽然结果还不如选一段
				for (int j = i; j <= n; j++) {

					//now不一定是最优的,now是在不断的尝试now或是max_pre加新的值
					now[j] = max(now[j - 1] + num[j], pre[j - 1] + num[j]);
					//每一个pre[j-1]都是对于第i次,第j个数之前最优的
					pre[j - 1] = max_pre;
					
					//每行的最后一个数不一定是最大的,max_pre才是
					if (now[j] > max_pre) {

						//max_pre取当前最大值
						max_pre = now[j];

					}
				}
			}

			System.out.println(max_pre);

		}
	}

	public static int max(int a, int b) {
		if (a > b)
			return a;
		return b;
	}

}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
该资源内项目源码是个人的课程设计、毕业设计,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96分,放心下载使用! ## 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),仅供学习参考, 切勿用于商业用途。 该资源内项目源码是个人的课程设计,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96分,放心下载使用! ## 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),仅供学习参考, 切勿用于商业用途。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值