最长上升子序列
int mx = 1; // 找出所计算的f[i]之中的最大值,边算边找
for (int i = 0; i < n; i++) {
f[i] = 1; // 设f[i]默认为1,找不到前面数字小于自己的时候就为1
for (int j = 0; j < i; j++) {
if (w[i] > w[j]) f[i] = max(f[i], f[j] + 1); // 前一个小于自己的数结尾的最大上升子序列加上自己,即+1
}
mx = max(mx, f[i]);
}
cout << mx << endl;
最长公共子序列
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(s1[i]==s2[j])
f[i][j]=f[i-1][j-1]+1;
else {
f[i][j]=max(f[i-1][j],f[i][j-1]);
}
}
}
cout<<f[n][m]<<endl;
最长公共上升子序列
f[i][j]代表所有a[1 ~ i]和b[1 ~ j]中以b[j]结尾的公共上升子序列的集合;
f[i][j]的值等于该集合的子序列中长度的最大值;
maxv是满足a[i] > b[k]的f[i - 1][k] + 1的前缀最大值。
可以直接将maxv提到第一层循环外面,减少重复计算,此时只剩下两重循环。
for (int i = 1; i <= n; i ++ )
{
int maxv = 1;
for (int j = 1; j <= n; j ++ )
{
f[i][j] = f[i - 1][j];
if (a[i] == b[j]) f[i][j] = max(f[i][j], maxv);
if (a[i] > b[j]) maxv = max(maxv, f[i - 1][j] + 1);
}
}
int res = 0;
for (int i = 1; i <= n; i ++ ) res = max(res, f[n][i]);
拦截导弹
#include<sstream>
#include<iostream>
#include<algorithm>
using namespace std;
const int N=1010;
int n,h[N],f[N],q[N];
int main(){
string line;
getline(cin, line);
stringstream ssin(line);
while (ssin >> h[n]) n ++ ;
while (ssin >> h[n]) n ++ ;
int res = 0, cnt = 0;
for (int i = 0; i < n; i ++ ){
f[i] = 1;
for(int j=0;j<i;j++)
if(h[i]<=h[j])
f[i] = max(f[i], f[j] + 1);
res = max(res, f[i]);
int k = 0;
while (k < cnt && q[k] < h[i]) k ++ ;//q记录系统尾巴的导弹高度
if (k == cnt) q[cnt ++ ] = h[i];//k到cnt了,q[cnt-1]变成当前这套系统的尾巴
else q[k] = h[i];//没到,换个尾巴
}
printf("%d\n", res);
printf("%d\n", cnt);
return 0;
}
389 207 155 300 299 170 158 65
组一 389 207 155 65 组二 300 299 170 158
一套防御系统的导弹拦截高度要么一直 严格单调 上升要么一直 严格单调 下降。
迭代加深+普通 541ms 时间O(n2^n) 空间O(n)
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 60;
int n;
int h[N];
int up[N], down[N];
bool dfs(int depth, int u, int su, int sd) {
// depth 序列上限, su, sd, u 上一个数或者下一个数
if (su + sd > depth) return false; // 9 > 8, 深度从0开始
if (u == n) return true;
// 枚举所有选法
// 枚举上升子序列
bool flag = false;
for (int i = 1; i <= su; i ++) // 上升子序列
if (up[i] < h[u]) {
int t = up[i];
up[i] = h[u];
if (dfs(depth, u + 1, su, sd)) return true;
up[i] = t;
flag = true;
break;
}
if (!flag) {
up[su + 1] = h[u];
if (dfs(depth, u + 1, su + 1, sd)) return true;
}
// 枚举下降子序列
flag = false;
for (int i = 1; i <= sd; i ++)
if (down[i] > h[u]) {
int t = down[i];
down[i] = h[u];
if (dfs(depth, u + 1, su, sd)) return true;
down[i] = t;
flag = true;
break;
}
if (!flag) {
down[sd + 1] = h[u];
if (dfs(depth, u + 1, su, sd + 1)) return true;
}
return false;
}
int main() {
while (cin >> n, n) {
for (int i = 0; i < n; i ++) cin >> h[i];
int depth = 0;
while (!dfs(depth, 0, 0, 0)) depth ++;
cout << depth << endl;
}
return 0;
}
dfs 560ms 时间O(n2^n) 空间O(n)
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 55;
int n;
int q[N];
int up[N], down[N];
int ans;
void dfs(int u, int su, int sd) {
if (su + sd >= ans) return; // ans不可能再小了
if (u == n) {
ans = su + sd; // su, sd 分别表示 len(up[]), len(down[])
return;
}
// 情况1:将当前数放到上升子序列中
int k = 0;
while (k < su && up[k] >= q[u]) k ++;
int t = up[k];
up[k] = q[u];
if (k < su) dfs(u + 1, su, sd);
else dfs(u + 1, su + 1, sd);
up[k] = t;
// 情况2:将当前数放到下降子序列中。
k = 0;
while (k < sd && down[k] <= q[u]) k ++;
t = down[k];
down[k] = q[u];
if (k < sd) dfs(u + 1, su, sd);
else dfs(u + 1, su, sd + 1);
down[k] = t;
}
int main() {
while (cin >> n, n) {
for (int i = 0; i < n; i ++)
cin >> q[i];
ans = n;
dfs(0, 0, 0);
cout << ans << endl;
}
}
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int N = 55;
int n;
int up[N], down[N], a[N];
bool dfs(int depth, int u, int su, int sd) {
if (su + sd > depth) return false;
if (u == n) return true; // u表示的是枚举每个顶点
if (!su || up[su] >= a[u]) {
up[su + 1] = a[u];
if (dfs(depth, u + 1, su + 1, sd)) return true;
} else {
int l = 1, r = su;
while (l < r) { // 坐标
int mid = (l + r) >> 1;
if (up[mid] < a[u]) r = mid;
else l = mid + 1;
}
int t = up[l];
up[l] = a[u];
if (dfs(depth, u + 1, su, sd)) return true;
up[l] = t;
}
if (!sd || down[sd] <= a[u]) {
down[sd + 1] = a[u];
if (dfs(depth, u + 1, su, sd + 1)) return true;
} else {
int l = 1, r = sd;
while (l < r) {
int mid = (l + r) >> 1;
if (down[mid] > a[u]) r = mid;
else l = mid + 1;
}
int t = down[l];
down[l] = a[u];
if (dfs(depth, u + 1, su, sd)) return true;
down[l] = t;
}
return false;
}
int main() {
while (cin >> n, n) {
for (int i = 0; i < n; i ++) cin >> a[i];
int depth = 0;
while (!dfs(depth, 0, 0, 0)) depth ++;
cout << depth << endl;
}
return 0;
}