hdu Super Jumping! Jumping! Jumping!

这个题目是一个DP的题目,求的就是给定序列中递增子序列的最大和值,但是除了用DP做之外还可以用线段树来做,是个很神奇的事情。



一、DP

DP的思路很简单,还是运用了我觉得是最优子结构和递推的思想,每次插入一个数字的的时候都保持前面序列的递增子序列和是最大的,即DP[i]保存的都是每个数字之前包括这个数字的最大递增子序列之和。每次插入一个数的时候,都判断这个数之前的序列里面是否有比现在这个数小的,如果有小的,且前面序列的最大和值加上自己本身的数值大于 自己,那么我们就把这个数字对应的DP[i]替换,DP方程描述的是,到目前这个位置,递增子序列的最大和值是多少。

这样的话,依次遍历整个序列之后,排下序,即可得到最大递增子序列的最大和值。


代码如下:

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int dp[1111];
int num[1111];
int n;
int comp ( const void *a, const void *b )           //降序排序//
{
    return * ( int * ) b - * ( int * ) a;
}
int main()
{
#ifndef ONLINE_JUDGE
	freopen("f:\\in.txt","r",stdin);
#endif
	int sum,max;
	int i, j, k;
	while(scanf("%d", &n)&&n)
	{
		for(i = 0; i < n; i++)
		{
			scanf("%d", &num[i]);
			dp[i] = 0;
		}
		dp[0] = num[0];
		for(j = 1; j < n; j++)
		{
			dp[j] = num[j];
			for(k = j - 1; k >= 0 ;k--)
				if(num[j] > num[k] && dp[k] + num[j] > dp[j])
					dp[j] = dp[k] + num[j];
		}
		qsort(dp, n, sizeof(dp[0]), comp);
		printf("%d\n", dp[0]);
	}
	return 0;
}

但是DP有一个缺点,就是如果这个题目的范围再给的大一点,N值再大的话,那么DP是个O(N*N)的算法,肯定会超时。所以我采用线段树来做。



二、线段树

线段树的思想就是当每次想插入一个数值的时候,都要先求1到这个数值之前的最大值,然后把这个最大值加上这个数值更新进线段树,保证线段树的每个叶子节点保存的都是到当前位置为止递增子序列的最大和值,每个非叶子节点保存的都是每个分区间里面的最大值,在pushup和query操作的时候当然做的是求区间最大值的操作,不是求和或者单纯的更新子树的和值。



#include<string.h>
#include<stdio.h>
#include<stdlib.h>
#include<map>
#include<algorithm>
using namespace std;
#define lson l , m , rt << 1
#define rson m + 1 , r , rt << 1 | 1
const int maxn = 2222;
int MAX[maxn<<2];
int num[2222];
int temp[2222];
#define max(x,y) (x) > (y) ? (x) : (y)
void PushUP(int rt) {
	MAX[rt] = max(MAX[rt<<1] , MAX[rt<<1|1]);
}
void build(int l,int r,int rt) {
	MAX[rt] = 0;
	if (l == r) {
		return ;
	}
	int m = (l + r) >> 1;
	build(lson);
	build(rson);
	PushUP(rt);
}
void update(int p,int sc,int l,int r,int rt) {
	if (l == r) {
		MAX[rt] = sc;
		return ;
	}
	int m = (l + r) >> 1;
	if (p <= m) update(p , sc , lson);
	else update(p , sc , rson);
	PushUP(rt);
}
int query(int L,int R,int l,int r,int rt) {
	if(L>R) return 0;
	if (L <= l && r <= R) {
		return MAX[rt];
	}
	int m = (l + r) >> 1;
	int ret = 0;
	if (L <= m) ret = max(ret , query(L , R , lson));
	if (R > m) ret = max(ret , query(L , R , rson));
	return ret;
}
int comp ( const void *a, const void *b )           //降序排序//
{
    return * ( int * ) a - * ( int * ) b;
}  
int binsrch(int *r,int n,int k)
{    
	int low,high,mid,found;
	low=1;  
	high=n; 
	found=0;
	while((low<=high)&&(found==0))
	{     mid=(low+high)/2;
	if(k>r[mid])  
		low=mid+1;
	else 
		if(k==r[mid]) 
			found=1;
		else   
			high=mid-1;
	}   
	if(found==1)
		return(mid);
	else
		return(0);
}
int main()
{
	int i,j,k;
	int n,N;
	int flag1,flag2;
	int pos;
	while(scanf("%d", &n)&&n)
	{
		/*map<int,int> ST;                     //注释掉的部分是用STL容器做的,是周队给我拍的,我还没研究透//
		map<int,int>::iterator it;
		for(i = 1; i<= n; i++)
		{
			scanf("%d", &num[i]);
			ST[num[i]]=1;
		}
		for(i=0,it=ST.begin();it!=ST.end();it++)
		{
			it->second=++i;
		}
		N=i;
		build(1, N, 1);
		for(i = 1; i <= n; i++)
		{
			flag1 = query(1,ST[num[i]]-1,1,N,1);
			update(ST[num[i]],num[i]+flag1,1,N,1);
		}
		printf("%d\n", MAX[1]);*/
		build(1,1000,1);
		for(i = 1; i<= n ;i++)
		{
			scanf("%d", &num[i]);
			temp[i] = num[i];
		}
		sort(temp+1,temp+n+1);
		for(j = 1; j <= n ;j++)
		{
			flag2 = binsrch(temp, n, num[j]);
			flag1 = query(1, flag2-1, 1, 1000, 1);
			update(flag2, flag1 + num[j], 1, 1000, 1);
		}
		printf("%d\n", MAX[1]);

	}
	return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值