Description
小V是中南大学图书馆的图书管理员,每天要整理很多同学们还回来的书。久而久之,他认识了很多常来图书馆的同学,比如说小L。简而言之吧,就是小V喜欢上了小L,并且想在下一次她来还书的时候表白。
小V的创意还是不错的,他精心准备了各种材料,打算构成“L”,“O”,“V”,“E”四个字母,在小L来的时候悄悄组合起来给她看。但是意外来了:在小L来的时候,小V只准备好了“L”,“O”,和“E”,“V”还没有拼好!但是机智的小V立刻想到了一个办法:他可以随手把旁边别人还的书合在一起,并且抽掉其中一部分,令剩下的书的高度构成了一个“V”形。
那么问题来了:已知N本书的高度,在不改变他们的顺序的前提下,能不能得到小V想要的“V”,如果可以的话,最少去掉多少本书呢?
(组成“V”的前提:h1>h2...<hn,即整个高度必须先递减再递增)
Input多组数据,第一行有一个整数T,表示有T组数据。(T<=100)
以下每组数据第一行有一个整数N,表示这一排书的数量。(1<=N<=100)
然后接下来一行是N个整数,h1,h2...hn分别代表每本书的高度。(1<=hi<=100)
Output
如果可以构成”V”,输出“HAPPY”,并在下一行输出所需拿掉的最少数量。
如果不能,输出“SAD”。
Sample Input7
3
3 2 3
4
3 2 4 3
5
1 2 4 6 7
1
22
2
25 8
3
98 16 68
4
88 14 82 69Sample Output
HAPPY
0
HAPPY
1
SAD
SAD
SAD
HAPPY
0
HAPPY
1
【题意】给出每本书的高度。求使其变成V型至少需要拿掉几本书。
【分析】求两端的最长递增子序列。dp。递推公式:
dp[ i ]以序列中第i个元素结尾的最长上升子序列的长度
那么状态转移方程为:if (a[i] > a[j]) dp[i] = max (dp[i], dp[j] + 1);
【代码】
#include<bits/stdc++.h>
using namespace std;
int dp[105],a[105],b[105];
/*求最长递增子序列*/
int ff(int a[],int n)
{
int p=1;
memset(dp,0,sizeof dp);
dp[0]=1;
for(int i=1;i<n;i++)
{
for(int j=0;j<i;j++)
{
if(a[i]>a[j])
dp[i]=max(dp[i],dp[j]+1);
}
}
for(int i=0;i<n;i++)
p=max(p,dp[i]);
return p;
}
main()
{
int T;scanf("%d",&T);
while(T--)
{
int n;
scanf("%d",&n);
for(int i=0;i<n;i++)
{
scanf("%d",&a[i]);
b[n-1-i]=a[i];
}
int l=-1,r1=1,l1=1;
for(int i=1;i<n-1;i++)
{
r1=ff(a+i,n-i);
l1=ff(b+n-1-i,i+1);
if(r1==1||l1==1) continue;
l=max(r1+l1-1,l);
}
if(l!=-1)printf("HAPPY\n%d\n",n-l);
else printf("SAD\n");
}
}