这个题目是一个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;
}