洛谷 P1091 NOIP 2004 合唱队形(动态规划)
题目适合已经有一定动态规划基础的去做,如果从未了解过动态规格请看我的另一篇博客:
排合唱队形就是中间高两边递减,给出思路:
求每一个位置i的两个值:
一个是从0到末尾的最长递增子序列dpl[i]
dpl[0]=1;
for(i=1;i<N;i++){
int max=0,w;
for(w=0;w<i;w++){
if(a[w]<a[i]&&dpl[w]>max)max=dpl[w];
}
dpl[i]=max+1;
}
一个是从末尾到0的最长递增子序列dpr[i]
dpr[N-1]=1;
for(i=N-2;i>=0;i--){
int max=0,w;
for(w=i+1;w<N;w++){
if(a[i]>a[w]&&dpr[w]>max)max=dpr[w];
}
dpr[i]=max+1;
}
对于位置i,dpl[i]是0到i的最长递增子序列,dpr[i]是i到末尾的最长递减子序列
那么位置i需要的人数便是sum[i]=dpl[i]+dpr[i]-1(减一是因为两次都把i算在内)
最后求sum[]数组的最大值便是所需的最多人数,用总人数减去便是答案。
完整代码如下:
#include<iostream>
#include<cstring>
const int M=105;
int a[M],dpl[M],dpr[M];
using namespace std;
int main(){
int N,i,n;
int lin1,lin2;
cin>>N;
for(i=0;i<N;i++)cin>>a[i];
dpl[0]=1;
for(i=1;i<N;i++){
int max=0,w;
for(w=0;w<i;w++){
if(a[w]<a[i]&&dpl[w]>max)max=dpl[w];
}
dpl[i]=max+1;
}
dpr[N-1]=1;
for(i=N-2;i>=0;i--){
int max=0,w;
for(w=i+1;w<N;w++){
if(a[i]>a[w]&&dpr[w]>max)max=dpr[w];
}
dpr[i]=max+1;
}
int max=-1,sum;
for(i=0;i<N;i++){
sum=dpl[i]+dpr[i];
if(sum>max)max=sum;
}
max-=1;
printf("%d",N-max);
return 0;
}
//大一菜鸟,有错误欢迎评论ヾ(๑╹◡╹)ノ"ヾ(๑╹◡╹)ノ"