NYOJ 整理图书(动态规划)

描述
小明是图书鹳狸猿,他有很多很多的书堆在了一起摆在了架子上,每摞书是横着放的,而且每摞书是订好的
是一个整体,不可分开,(可以想象架子是一条直线),但是这些书高度却参差不齐,小明有强迫症,看不得不整齐
所以他想让这些书的高度形成一个非降序列他才舒心,可是这些书是有序的,所以他只能把其中的一摞书和他相邻的书装订在一起
形成一摞新的书,那么他最少的装订次数是多少呢
输入
多组测试数据,处理到文件结束
每组数据开始有一个n(1<=n<=1000)表示有n摞书
接下来一行是这n摞书的高度a[i],(1<=a<=10^5)(虽然这个高度有点扯淡)
输出
首先输出Case num : 表示第几组数据
接下来对于每组数据输出最少的装订次数
样例输入
5
8 2 7 3 1
1
100
样例输出
Case 1: 3

Case 2: 0

 

dp[i]表示前i本书所要的最小次数,叠成非降序列所需要的最小次数。答案即dp[n],很简单因为有n本嘛。

先来分析一下这道题,这道题总体就是动态规划,是属于‘记录结果再利用’型的动态规划。就是本次(即第i个)的最优值依赖于前面所有以求出来的最大值,算法复杂度大致为O(n*n); 

详解一下第i个时选择的策略,第i个可以单独1摞书,可以从第i个往前数2本放一摞,也可以从第i个往前数3本放一摞.....一次类推,设j<i and 0<j<i, 则可以考虑从第j个到第i个放一摞,所以dp[i]=dp[j-1]+i-j;(因为j到i一共有i-j+1本,只要叠i-j次);其实说白了就是根据当前点不断的枚举之前已经求出来的值。

代码实现的时候就是这样的,h[i]记录为当前最优最高方法下的最高的一摞书,所以第考虑前i个的时候要注意和要大于等于前面记录的h,所以边更新边记录。

 

 

AC代码:

 

 

# include <cstdio>
# include <cstring>
# include <algorithm>
using namespace std;
int a[1010], dp[1010], h[1010], sum[1010];
int main(){
	int i, j, k, n, t;
	t=0;
	while(scanf("%d", &n)!=EOF){
		sum[0]=0;
		for(i=2; i<=n; i++){
			dp[i]=2000000000;
			h[i]=-2000000000;
		}
		for(i=1; i<=n; i++){
			scanf("%d", &a[i]);
			sum[i]=sum[i-1]+a[i];
		}
	    h[0]=0;h[1]=a[1];dp[1]=0;dp[0]=0;
	    for(i=2; i<=n; i++){
	    	for(j=1; j<=i; j++){
	    		if(sum[i]-sum[j-1]>=h[j-1]){
	    			if(dp[j-1]+i-j<dp[i]){
	    				dp[i]=dp[j-1]+i-j;
	    				h[i]=sum[i]-sum[j-1];
					}
					if(dp[j-1]+i-j==dp[i]){
						h[i]=min(h[i], sum[i]-sum[j-1]);
					}
				}
			}
		}
		printf("Case %d: %d\n", ++t, dp[n]);
	}
	return 0;
}

 

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值