一道想不出来的题

题源·http://acm.hrbust.edu.cn/vj/index.php?c=contest-contest&cid=141#problem/5

E - Super Jumping! Jumping! Jumping!

Time Limit: 1000 MS Memory Limit: 32768 KB

64-bit integer IO format: %I64d , %I64u Java class name: Main

[Submit] [Status]

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 2
4 1 2 3 4
4 3 3 2 1
0

Sample Output

4
10
3
这道题让我好苦恼呀,错误代码

#include<stdio.h>
int main()
{
    int dp[1010];
    int a[1010];
    int n,i,sum,sum1,j;
    while(scanf("%d",&n)!=EOF)
    {
        if(n==0)
          return 0;
        for(i=0;i<n;i++)
            scanf("%d",&a[i]);
        for(i=0;i<n;i++)
           dp[i]=0;
        sum=a[0];
        for(i=1;i<n;i++)
        {
            sum1=a[i];
            for(j=0;j<i;j++)
            {
                if(a[i]>a[j]&&dp[i]<dp[j]+1)
                {
                    printf("%d ",a[j]);
                    dp[i]=dp[i]+1;
                    sum1=sum1+a[j];
                }
            }
            printf("\n%d\n",sum1);
            if(sum<sum1)
            {
                 sum=sum1;
               //  printf("0000");
            }
        }
       // printf("%d %d\n",a[0],a[n-1]);
        printf("%d\n",sum);
    }
    return 0;


}

借用求最长递增子序列,在每组求和,发现了错误

7

1 7 3 5 9 4 8

是错误的·

看了别人的代码

正确的思路

即求最大升序子串,可以不连续,但是s[i]一定要大于s[i-1]。
思路是从后面开始算,把每个以此位置为起点的最大升序子串的和求出来,存DP数组里。比如只有1 2 99 97 98这三个元素(同时这也是一组易错的数据),那就从98开始算,98的最大升序子串和显然是98,所以DP[4]=98。然后开始算97, 97的算法是找出它后面所有比它大的,然后比较它们的DP值,取最大的那一个,加上97即可,因为后面只有一个98,98大于97,所以97这个位置的DP值就是97 + 98,即以97为起点的升序子串为97 98。再算99,后面所有数都比它小,不可取,所以DP值是它本身。又算2,显然后面的所有数都比它大,所以都可以取,但是我们要取DP值最大那个,即97的(195),同理,1也是这么算,最后算出来1的DP值是198,最大,就取它了。推广到一般情况,最后算出答案后要遍历一次DP数组,因为最后的答案可能不是以第一个元素为起点。
 
 1 #include<stdio.h>
 2 #include<stdlib.h>
 3 #include<string.h>
 4 #define    MAX    1005
 5 
 6 int    main(void)
 7 {
 8     int    n;
 9     int    s[MAX];
10     int    dp[MAX],max,ans;                        //dp[i]存的是以i为起点的最大升序子串的和
11 
12     while(scanf("%d",&n) && n)
13     {
14         for(int i = 0;i < n;i ++)
15             scanf("%d",&s[i]);
16 
17         ans = dp[n - 1] = s[n - 1];
18         for(int i = n - 2;i >= 0;i --)            
19         {
20             max = 0;
21             for(int j = i + 1;j < n;j ++)         //看s[i]后面哪一个子串是s[i]可以加进去的,找出所有这样的子串,取DP值最大那个
22                 if(s[i] < s[j] && max < dp[j])
23                     max = dp[j];
24             dp[i] = s[i] + max;
25 
26             ans = ans < dp[i] ? dp[i] : ans;
27         }
28         ans = ans < 0 ? 0 : ans;                 //注意可以从起点直接跳终点,此时值为0,若是算出最终值是负数的话要选此方案
29         
30         printf("%d\n",ans);
31     }
32 
33     return    0;
34 }

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值