洛谷 P1091 NOIP 2004 合唱队形(动态规划)

题目适合已经有一定动态规划基础的去做,如果从未了解过动态规格请看我的另一篇博客:

love_phoebe的博客 求单调递增最长子序列

排合唱队形就是中间高两边递减,给出思路:

求每一个位置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;
}

//大一菜鸟,有错误欢迎评论ヾ(๑╹◡╹)ノ"ヾ(๑╹◡╹)ノ"

posted @ 2017-07-24 09:25  琳小羽  阅读(145)  评论(0编辑  收藏  举报