1017. 怪盗基德的滑翔翼
分析
1.随意选个楼顶作为起点。
2.随意选个方向,选定方向就固定了。
这两点确定了之后,假定以 a[i] 为起点,则最长距离就是以 a[i] 为结尾的最长上升子序列。在两个方向上(左到右,右到左)各求一次最长上升子序列即可。
注意
求当前点开始的最长下降子序列的时候, 要注意递推的顺序, 因为先得到后面点的状态, 才可以推出当前的状态
code
#include <iostream>
#include <cstring>
using namespace std;
const int N = 110;
int a[N], f[N];
int n;
int main(){
int T;
cin >> T;
while (T --){
cin >> n;
memset(a, 0, sizeof a);
for (int i = 1; i <= n; i ++ ) cin >> a[i];
int res = 1;
for (int i = 1; i <= n; i ++ ){
f[i] = 1;
for (int j = 1; j < i; j ++ )
if (a[j] < a[i])
f[i] = max(f[i], f[j] + 1);
res = max(res, f[i]);
}
for (int i = n; i >= 1; i -- ){
f[i] = 1;
for (int j = n; j > i; j -- )
if (a[j] < a[i])
f[i] = max(f[i], f[j] + 1);
res = max(res, f[i]);
}
cout << res << endl;
}
return 0;
}
1014. 登山
分析
模板题
- 编号递增----->必须是个子序列
- 不连续浏览海拔相同的两个景点
- 一旦开始下山,就不再向上走------->路线是先严格上升再严格下降
code
#include <iostream>
using namespace std;
const int N = 1010;
int a[N], f[N], g[N];
int n;
int main(){
scanf("%d", &n);
for (int i = 0; i < n; i ++ ) scanf("%d", &a[i]);
for (int i = 0; i < n; i ++ ){
f[i] = 1;
for (int j = 0; j < i; j ++ )
if (a[j] < a[i]) f[i] = max(f[i], f[j] + 1);
}
for (int i = n - 1; i >= 0; i -- ){
g[i] = 1;
for (int j = n - 1; j > i; j -- )
if (a[j] < a[i]) g[i] = max(g[i], g[j] + 1);
}
int res = 0;
for (int i = 0; i < n; i ++ )
res = max(res, f[i] + g[i] - 1);
cout << res << endl;
return 0;
}
482. 合唱队形
分析
同上题的方法
code
#include <iostream>
using namespace std;
const int N = 1010;
int a[N], f[N], g[N];
int main(){
int n;
scanf("%d", &n);
for (int i = 0; i < n; i ++ ) scanf("%d", &a[i]);
for (int i = 0; i < n; i ++ ) {
f[i] = 1;
for (int j = 0; j < i; j ++ )
if (a[j] < a[i]) f[i] = max(f[i], f[j] + 1);
}
for (int i = n - 1; i >= 0; i -- ) {
g[i] = 1;
for (int j = n - 1; j > i; j -- )
if (a[j] < a[i]) g[i] = max(g[i], g[j] + 1);
}
int res = 0;
for (int i = 0; i < n; i ++ ) res = max(res, f[i] + g[i] - 1);
cout << n - res << endl;
return 0;
}
1012. 友好城市
分析
其实题目问的就是, 给了南北的连线, 怎么样取到最多的连线, 且不相交
样例模拟:
找出最多的航道
用pair<int, int>
存储, 然后排序, 找到排序后的第2个变量的最长上升子序列
code
#include <iostream>
#include <algorithm>
using namespace std;
typedef pair<int, int> PII;
const int N = 5010;
PII a[N];
int n;
int f[N];
int main(){
scanf("%d", &n);
for (int i = 0; i < n; i ++ ) scanf("%d%d", &a[i].first, &a[i].second);
sort(a, a + n);
for (int i = 0; i < n; i ++ ) {
f[i] = 1;
for (int j = 0; j < i; j ++ )
if (a[j].second < a[i].second) f[i] = max(f[i], f[j] + 1);
}
int res = 0;
for (int i = 0; i < n; i ++ ) res = max(res, f[i]);
cout << res << endl;
return 0;
}
code(O(nlogn)做法)
#include <iostream>
#include <algorithm>
using namespace std;
typedef pair<int, int> PII;
const int N = 5010;
PII a[N];
int n;
int q[N];
int main(){
scanf("%d", &n);
for (int i = 0; i < n; i ++ ) scanf("%d%d", &a[i].first, &a[i].second);
sort(a, a + n);
int len = 0;
for (int i = 0; i < n; i ++ ) {
int l = 0, r = len;
while (l < r) {
int mid = l + r + 1 >> 1;
if (q[mid] < a[i].second) l = mid;
else r = mid - 1;
}
q[l + 1] = a[i].second;
len = max(len, l + 1);
}
cout << len << endl;
return 0;
}
1016. 最大上升子序列和
分析
直接将最长上升子序列的属性改为最大和即可
code
#include <iostream>
using namespace std;
const int N = 1010;
int a[N], n;
int f[N];
int main(){
scanf("%d", &n);
for (int i = 0; i < n; i ++ ) scanf("%d", &a[i]);
for (int i = 0; i < n; i ++ ){
f[i] = a[i];
for (int j = 0; j < i; j ++ )
if (a[j] < a[i])
f[i] = max(f[i], f[j] + a[i]);
}
int res = 0;
for (int i = 0; i < n; i ++ ) res = max(res, f[i]);
cout << res << endl;
return 0;
}