hdu2198 How many elements you must throw out? C语言动态规划题

hdu2198 How many elements you must throw out? C语言动态规划题

原题链接http://acm.hdu.edu.cn/showproblem.php?pid=2198

Problem Description
You have a sequence of numbers from which you must create the longest subsequence satisfying the following condition: it can be ‘cut’ into two parts that share exactly one common element (the last element of the first part is the first element of the second part), and the first part is sorted in strictly ascending order while the second part is sorted in strictly descending order. For example, the sequence { 1, 4, 6, 5, 2, 1 } can be ‘cut’ into { 1, 4, 6 } and { 6, 5, 2, 1 }. The two parts share the 6(see the following graph), and the first sequence is sorted in ascending order while the second sequence is sorted in descending order.

在这里插入图片描述
You are given a sequence of numbers. Output the minimal number of elements you must throw out from the given sequence such that the remaining subsequence satisfies the condition described above.

Input
There are multiple test cases. At first line of each case, there’s an integer N (1<=N<=50) and N integers followed at second line representing the subsequence, each of which ranges from 1 to 1000000000.Input ends when N is 0.

Output
Output the result for each case in one line.

Sample Input
6
1 4 6 5 2 1
5
2 2 2 2 2
0

Sample Output
0
4

题目意思
上面所说的大概就是一段连续数列中你要找出一个数,将这个数列从这个数分成两部分,然后前一个数列末尾数据是这个数,后一个数列开头是这个数。然后要满足前一个数列是递增的,后一个数列是递减的,如果不存在则删去某几个数使得这两个数列存在。求最少要删去几个数。

读懂题目其实很简单,其实就是求在某个数将该数列分成两个数列后,前一段数列的最长递增子序列(非连续)和后一段数列的最长递减子序列(非连续)的长度之和的最大值。

比如1 4 6 5 2 1,当选定数据6时候,分成 1 4 6和6 5 2 1两组数据,这时候他们的最长子序列分别是1 4 6和6 5 2 1,这时候就输出6(原先数列长度)+1(有一个数据重复)-3(前一段递增子序列长度)-4(后一段递减子序列长度)=0。
又比如5 4 3 2 1 2 3 4 5。将它分成九种不同的两段数列。当数据为第一个5(或者最后一个5)时,分成两个子数列分别为5以及
5 4 3 2 1 2 3 4 5。这时候前一个最长子序列是2(本身),长度为1,后一个最长子序列是5 4 3 2 1,长度为5。
输出结果就是9+1-1-5=4。

由于数据数量比较少(我自己很菜也不知道除了这个办法有什么办法),将数列中每一个数遍历,然后求如果当前这个数是分割数的时候,两个数列里递增(递减)最长子序列长度之和,然后与求得的相比较求出最大值。

代码如下

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;

double a[55],b[55],dp1[55],dp2[55];

int main()
{
	int n;
	while(scanf("%d",&n)!=EOF&&n)
	{
		int mx=0;
		for(int i=0;i<n;i++)
		scanf("%lf",&a[i]);
		int pos;// 用于记录当前分割位置
		for(int k=0;k<n;k++){
		pos=k;
		int f=0;
		for(int i=n-1;i>=pos;i--)
		{
			b[f++]=a[i];  //将后半部分求递减数列部分逆置变为求递增数列便于理解
		}
		
		for(int i=0;i<=50;i++)
		dp1[i]=1;   //将dp数组内元素初始化为1,因为如果前面没有元素满足比它小(大)时,它本身算为一个长度
		int MAX1=1; //记录前一段数列中最长递增子序列的长度
		for(int i=0;i<=pos;i++)
		{
		    for(int j=0;j<i;j++)
			{
				if(a[i]>a[j])
				{
					dp1[i]=max(dp1[i],dp1[j]+1);  
//dp1[j]代表到j位置的数时最长的子序列长度,如果a[i]比a[j]长,那么此时dp[i]的最长子序列长度为dp[j]+1或者位置j之前更长的子序列
					if(dp1[i]>MAX1)
					MAX1=dp1[i];
				}
			}
		} 
		
		for(int i=0;i<=50;i++)
		dp2[i]=1;
		int MAX2=1;
		for(int i=0;i<f;i++)
		{
			for(int j=0;j<i;j++)
			{
				if(b[i]>b[j])
				{
					dp2[i]=max(dp2[i],dp2[j]+1);   //同上
					if(dp2[i]>MAX2) 
					MAX2=dp2[i];
				}
			}
		}
		
		if(MAX1+MAX2>mx)
		mx=MAX1+MAX2;       //记录下最长的两部分子序列长度和
		}
		printf("%d\n",n+1-mx);  //由于有重复部分故需+1
	}
	return 0;
}

by有点弱智的鲤鱼王

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值