加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

**hdu 2198 How many elements you must throw out? C语言动态规

发布时间:2020-12-15 04:50:34 所属栏目:百科 来源:网络整理
导读:hdu 2198 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 foll

hdu 2198 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,6 } and { 6,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


Sample Output


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以及1


5 4 3 2 1 2 3 4 5。这时候前一个最长子序列是2(本身),长度为1,后一个最长子序列是5 4 3 2 1,长度为5。


输出结果就是9+1-1-5=4。

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

代码如下

#include

#include

#include

#include

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

scanf("%lf",&a[i]);

int pos;// 用于记录当前分割位置

for(int k=0;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

{

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

{

for(int j=0;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("%dn",n+1-mx); //由于有重复部分故需+1

}

return 0;

}

by有点弱智的鲤鱼王

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读