hdu Super Jumping! Jumping! Jumping!

来源:互联网 发布:算法基础 打开算法之门 编辑:程序博客网 时间:2024/06/08 15:11

                              Super Jumping! Jumping! Jumping!

                              Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
                              Total Submission(s): 17669 Accepted Submission(s): 7573


Problem Description
Nowadays, a kind of chess game called “Super Jumping! Jumping! Jumping!” is very popular in HDU. Maybe you are a good boy, and know little about this game, so I introduce it to you now.



The game can be played by two or more than two players. It consists of a chessboard(棋盘)and some chessmen(棋子), and all chessmen are marked by a positive integer or “start” or “end”. The player starts from start-point and must jumps into end-point finally. In the course of jumping, the player will visit the chessmen in the path, but everyone must jumps from one chessman to another absolutely bigger (you can assume start-point is a minimum and end-point is a maximum.). And all players cannot go backwards. One jumping can go from a chessman to next, also can go across many chessmen, and even you can straightly get to end-point from start-point. Of course you get zero point in this situation. A player is a winner if and only if he can get a bigger score according to his jumping solution. Note that your score comes from the sum of value on the chessmen in you jumping path.
Your task is to output the maximum value according to the given chessmen list.

Input
Input contains multiple test cases. Each test case is described in a line as follow:
N value_1 value_2 …value_N
It is guarantied that N is not more than 1000 and all value_i are in the range of 32-int.
A test case starting with 0 terminates the input and this test case is not to be processed.

Output
For each case, print the maximum according to rules, and one line one case.

Sample Input
3 1 3 24 1 2 3 44 3 3 2 10

Sample Output
4103

Author
lcy


#include<iostream>#include<string.h>using namespace std;int num[10001];int sum[10001];int dp[10001]={0};int main(){    int n;    while(cin>>n)    {        if(n==0) break;        memset(num,0,sizeof(num));            memset(dp,0,sizeof(dp));        for(int i=1;i<=n;i++)        {            cin>>num[i];            dp[i]=num[i];        }        for(int i=1;i<=n;i++)        {            for(int j=1;j<i;j++)            {                if(num[i]>num[j]&&dp[i]<dp[j]+num[i])                dp[i]=dp[j]+num[i];            }        }        int max=0;        for(int i=1;i<=n;i++)        {            if(max<dp[i])            max=dp[i];        }        cout<<max<<endl;            }    return 0;} hdu 1087



总结:


最长上升子序列二分方法的思想(n*log(n))//利用二分将复杂度降低


用f【i】来保存的是长度为i 的最长上升子序列末位所能达到的最小值


注意 这里的i 是随着访问原数组不断进行更新的 它的最大值(即f 数组的大小 )就是最长上升子序列的长度



当我们访问到原数组(假如原数组是num[]),当访问到num[j] 时,原序列进行二分查找,目的是看是否存在一个值k 满足{f(k)<num[j]<=f[k+1];}(就是找到了比f[]中所有值都大的数,则要将其放入f[]中) 若存在,则f[k+1]=num[j],同时f的长度加一   如果不存在,替换相应的值,继续向后访问~




 二分方法只能用来找到最长上升子序列的长度 不能将最长上升子序列元素输出出来
F序列中记载的并不是真正的最长上升子序列,但其长度等同于最长上升子序列的长度。




最简单的理解是,由于我们对原数组都是依次进行访问的,如果当前的值num[正在访问]比f【已经存下】的所有元素的值都大,我们就放入,如果比f中的某个元素小,就将其对应代替,那么如果比f{所有元素}大就放,比f{所有元素}小就替换,访问到最后一个num[最后一个]时,f的长度正好就是最长公共子序列的长度~
 

#include<stdio.h>int z[1007],dp[1007];int main(){    int n,i,j;    scanf("%d",&n);    for(i=1; i<=n; i++)    {        scanf("%d",&z[i]);    }    dp[1]=z[1];    int left,right,lenth=1;    for(j=2; j<=n; j++)    {        left=1;        right=lenth;        while(left<=right)        {            int mid=(left+right)/2;            if(dp[mid]<z[j])            {                left=mid+1;            }            else right=mid-1;        }        dp[left]=z[j];        if(left>lenth)        lenth++;    }    printf("%d\n",lenth);    return 0;}




还有一个(n^2)的方法,也是基础方法:


它的思想是dp[i] 中保存的是1~i这段中 最长子序列的长度


dp[i]=max(dp[j])+1;


i>j,num[i]>num[j];


从给出的状态转移方程就可以看出,访问到num[i]时,不断用num【1~j】和num[i]相比较,如果小于num[i],那么当前的dp[i]肯定就是在dp[j]的基础之上加1


   
if(n>=10000) 
You can't finish it in less than a second


剩下的就是对代码的熟练度了~   






















原创粉丝点击