7-6 气球排序 (10 分)
题目
竞赛结束了,志愿者们闲得无聊就把剩余的气球按顺序从左到右挂在墙上,每个气球都有一个高度。
小明刚刚路过,看到了墙上挂了这么多的气球,就说:“要是这些气球的位置(高度)是按照从低到高排列该有多好!” 为了满足小明的愿望,志愿者们立刻准备去戳破一些气球(有点暴脾气),以便确保剩余的从左到右的气球位置满足由低到高排列。
“且慢!”,小明阻拦道,“你们这样处理效率太低了,应该先好好规划该戳破哪些气球,并且尽量减少需要戳破的气球数量!而且据我所知,这样的问题你们在算法课程中应该是学过的!另外,为了考验你们灵活应用知识的能力,我想再增加一个限制条件,就是中间那个气球不能戳破”。
志愿者们毕竟不擅长算法设计,只能请你帮忙。 到底需要最少戳破多少个气球才能确保剩余的气球位置满足由低到高排列,且保留中间那个气球呢?
说明:中间那个气球是这样规定的:若气球总数n是奇数,则中间位置就是(n+1)/2;若气球总数n是偶数,则中间位置就是n/2。
输入格式
输入数据首先包含一个整数T,表示测试实例的个数(T<=20),然后是T组测试数据。 每组测试数据的第一行是一个整数n,表示原始气球的总数。 测试数据第二行输入n个整数,分别代表每个气球的高度ai。 (1<=n<=20000 , 1<=ai<=100000)
输出格式
对于每组测试,输出最少需要戳破的气球数。
输入样例
3
5
1 3 5 4 7
6
3 3 7 4 5 8
5
5 4 3 1 3
输出样例:
1
3
4
基本思路
零基础的需要先看一下下面这一篇博文,传送门:
添加链接描述
LCS的题目如果只要求求最长长度maxLength,还是很模板化的。如果要求求具体路径,那就很麻烦了,可以参考一下我的这篇博文,传送门:
添加链接描述。
其中,求解LCS长度可以当成固定模板理解并记忆下来,很套路化。
代码
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
const int INF=0x3f3f3f3f;
int n;
int a[20005];
int greedy[20005];
int main(){
int t;
cin>>t;
while(t--){
int cntofbloom=0;
//初始化本组样例需要用到的数据结构
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
}
fill(greedy+1,greedy+n+1,INF);
//
int mid;
if(n%2) mid=(n+1)/2;
else mid=n/2;
int maxLength=0;//LCS的长度,初始化为0
for(int i=1;i<=n;i++){
//筛选(经过这一步,保证了a[mid]一定会被选入最终的LCS)
if(i<mid){
if(a[i]>a[mid]){
//说明这个a[i]是无效元素,不需要对它进行贪心+二分算法,直接跳过即可
continue;
}
}else if(i>mid){
if(a[i]<a[mid]){
//说明这个a[i]是无效元素,不需要对它进行贪心+二分算法,直接跳过即可
continue;
}
}
//经过上一步的筛选之后,对剩下来的序列进行贪心+二分算法,同时维护数组greedy
int posInGreedy=lower_bound(greedy+1,greedy+n+1,a[i])-greedy;
if(greedy[posInGreedy]==INF){
maxLength++;
}
greedy[posInGreedy]=a[i];
}
//输出
cout<<n-maxLength<<endl;
}
}