1017. 怪盗基德的滑翔翼
怪盗基德是一个充满传奇色彩的怪盗,专门以珠宝为目标的超级盗窃犯。
而他最为突出的地方,就是他每次都能逃脱中村警部的重重围堵,而这也很大程度上是多亏了他随身携带的便于操作的滑翔翼。
有一天,怪盗基德像往常一样偷走了一颗珍贵的钻石,不料却被柯南小朋友识破了伪装,而他的滑翔翼的动力装置也被柯南踢出的足球破坏了。
不得已,怪盗基德只能操作受损的滑翔翼逃脱。
假设城市中一共有N幢建筑排成一条线,每幢建筑的高度各不相同。
初始时,怪盗基德可以在任何一幢建筑的顶端。
他可以选择一个方向逃跑,但是不能中途改变方向(因为中森警部会在后面追击)。
因为滑翔翼动力装置受损,他只能往下滑行(即:只能从较高的建筑滑翔到较低的建筑)。
他希望尽可能多地经过不同建筑的顶部,这样可以减缓下降时的冲击力,减少受伤的可能性。
请问,他最多可以经过多少幢不同建筑的顶部(包含初始时的建筑)?
输入格式
输入数据第一行是一个整数K,代表有K组测试数据。
每组测试数据包含两行:第一行是一个整数N,代表有N幢建筑。第二行包含N个不同的整数,每一个对应一幢建筑的高度h,按照建筑的排列顺序给出。
输出格式
对于每一组测试数据,输出一行,包含一个整数,代表怪盗基德最多可以经过的建筑数量。
数据范围
1≤K≤100,
1≤N≤100,
0<h<10000
输入样例:
3
8
300 207 155 299 298 170 158 65
8
65 158 170 298 299 155 207 300
10
2 1 3 4 5 6 7 8 9 10
输出样例:
6
6
9
最长不下降序列和最长不上升子序列(算法思想相同,本题同时考察两个方向)
//参考最长不下降子序列代码模型
#include<bits/stdc++.h>
using namespace std;
const int N = 110;
int a[N];
int dp1[N], dp2[N]; //用来记录以序号I的结尾的序列中,最长不上升序列有多长
int main()
{
int K;
cin>>K;
for(int k = 0;k < K;k ++){
int n;
scanf("%d",&n);
for(int i = 1;i <= n;i ++){
scanf("%d",&a[i]);
}
int ans = -1;
for(int i = 1;i <= n;i ++){
dp1[i] = 1; //进行初始化,默认长度为1
dp2[i] = 1;
//依次递减(正向下降)
for(int j = 1;j < i;j ++){
if(a[j] > a[i] && dp1[j] + 1 > dp1[i]){
//如果存在比当前楼栋高,且加上a[i]后序列长度大于a[i]此时的值
dp1[i] = dp1[j] + 1;
}else if(a[j] < a[i] && dp2[j] + 1 > dp2[i]) {
dp2[i] = dp2[j] + 1;
}
}
ans = max(ans, dp1[i]);
ans = max(ans, dp2[i]);
}
cout<<ans<<endl;
}
return 0;
}
1014. 登山
五一到了,ACM队组织大家去登山观光,队员们发现山上一共有N个景点,并且决定按照顺序来浏览这些景点,即每次所浏览景点的编号都要大于前一个浏览景点的编号。
同时队员们还有另一个登山习惯,就是不连续浏览海拔相同的两个景点,并且一旦开始下山,就不再向上走了。
队员们希望在满足上面条件的同时,尽可能多的浏览景点,你能帮他们找出最多可能浏览的景点数么?
输入格式
第一行包含整数N,表示景点数量。
第二行包含N个整数,表示每个景点的海拔。
输出格式
输出一个整数,表示最多能浏览的景点数。
数据范围
2≤N≤1000
输入样例:
8
186 186 150 200 160 130 197 220
输出样例:
4
自己写的版本,通过但运行时间很长(因为寻找以当前字母为开头的递减序列的时候,外层循环中内嵌了一个双层循环,变成了三重循环)
#include<bits/stdc++.h>
using namespace std;
const int N = 1010;
int a[N];
int dp[4][N];
int main()
{
int n;
scanf("%d", &n);
for(int i = 1;i <= n;i ++){
scanf("%d", &a[i]);
dp[1][i] = dp[2][i] = 1;
}
n = unique(a + 1, a + n + 1) - (a + 1); //进行相邻元素去重
int ans = -1;
for(int i = 1;i <= n;i ++){
//呈山峰状,中间高两边低,往前找小的,往后也找小的
//找寻以a[i]结尾的不递减序列
for(int j = 1;j < i;j ++){
if(a[j] < a[i] && dp[1][j] + 1 > dp[1][i]){
dp[1][i] = dp[1][j] + 1;
}
}
//寻找以a[i]开头的不上升序列
for(int j = n - 1;j >= i;j --){
for(int k = n;k > j;k --){
if(a[k] < a[j] && dp[2][k] + 1 > dp[2][j]){
dp[2][j] = dp[2][k] + 1;
}
}
}
dp[3][i] = dp[1][i] + dp[2][i] - 1;
ans = max(ans, dp[3][i]);
}
cout<<ans;
return 0;
}
运行结果如下:
简化版本和自己写的版本思路是一模一样的,不一样的就是走三重循环那个部分抽出来走了第二次循环(想到过但是没实施)
新代码对时间的优化程度很高
//简化版本的思路是一样的,只是没有一次完成,也就没有了走三重循环的必要,直接拆成两次独立的双重循环
#include<bits/stdc++.h>
using namespace std;
const int N = 1010;
int a[N];
int f[N], g[N];
void dp(int f[],int n)
{
for(int i = 1;i <= n;i ++){
for(int j = 1;j < i;j ++){
if(a[j] < a[i])
f[i] = max(f[i], f[j] + 1);
}
}
}
int main()
{
int n;
scanf("%d", &n);
for(int i = 1;i <= n;i ++){
scanf("%d", &a[i]);
f[i] = g[i] = 1;
}
n = unique(a + 1, a + n + 1) - (a+1);
dp(f, n); //从低到高找一次
reverse(a + 1, a + n + 1);
dp(g, n); //再反向从a[n]到a[1]从低到高找一次,其实和原本的思路一样,但这里简化了过程
int ans = 0;
for(int i = 1;i <= n;i ++){
ans = max(ans, f[i] + g[n + 1 - i] - 1);
}
cout<<ans;
return 0;
}
482. 合唱队形(可跳过)
N位同学站成一排,音乐老师要请其中的 (N−K)位同学出列,使得剩下的 K位同学排成合唱队形。
合唱队形是指这样的一种队形:设 K位同学从左到右依次编号为 1,2…,K,他们的身高分别为 T1,T2,…,TK,则他们的身高满足
T 1 < … < T i > T i + 1 > … > T K ( 1 ≤ i ≤ K ) T_1<…<T_i>T_i+1>…>T_K ~(1≤i≤K) T1<…<Ti>Ti+1>…>TK (1≤i≤K)
你的任务是,已知所有N位同学的身高,计算最少需要几位同学出列,可以使得剩下的同学排成合唱队形。
输入格式
输入的第一行是一个整数 N,表示同学的总数。
第二行有 N个整数,用空格分隔,第 i i i个整数 T i T_i Ti是第 i i i 位同学的身高(厘米)。
输出格式
输出包括一行,这一行只包含一个整数,就是最少需要几位同学出列。
数据范围
2≤N≤100,
130≤Ti≤230
输入样例:
8
186 186 150 200 160 130 197 220
输出样例:
4
跟上题基本上一模一样,减去上题的答案即为所求
#include<bits/stdc++.h>
using namespace std;
const int N = 1010;
int a[N];
int f[N], g[N];
void dp(int f[],int n)
{
for(int i = 1;i <= n;i ++){
for(int j = 1;j < i;j ++){
if(a[j] < a[i])
f[i] = max(f[i], f[j] + 1);
}
}
}
int main()
{
int m;
scanf("%d", &m);
for(int i = 1;i <= m;i ++){
scanf("%d", &a[i]);
f[i] = g[i] = 1;
}
int n = unique(a + 1, a + m + 1) - (a+1);
dp(f, n);
reverse(a + 1, a + n + 1);
dp(g, n);
int ans = 0;
for(int i = 1;i <= n;i ++){
ans = max(ans, f[i] + g[n + 1 - i] - 1);
}
cout<<m - ans;
return 0;
}