标签:排序 最长公共子序列 problem 布局 分析 c++ printf 长度 遍历
dp[i] = max(dp[i], dp[j] + 1)
, j
必须要小于i
for(int i = 1; i <= n; i++) {
dp[i] = 1;
for(int j = 1; j < i; j++) {
if(a[i] > a[j]) {
dp[i] = max(dp[i], dp[j] + 1);
}
}
}
int res = 0;
for(int i = 1; i <= n; i++) res = max(res, dp[i]);
printf("%d ", res);
memset(tr, -1, sizeof tr);
for(int i = 1; i <= n; i++) {
dp[i] = 1;
for(int j = 1; j < i; j++) {
if(a[i] > a[j]) {
// 有更新
if(dp[i] < dp[j] + 1) {
dp[i] = dp[j] + 1;
tr[i] = j;
}
}
}
}
int ans = 0, sign = -1;
for(int i = 1; i <= n; i++) {
if(ans < dp[i]) {
ans = dp[i];
sign = i;
}
}
// 找到最终的以sign为结尾,长度为ans的序列
printf("%d %d\n", ans, sign);
int i = sign;
while(~i) {
cout << a[i] << " ";
i = tr[i];
}
res = max(res, f[i] + g[i] - 1)
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 5100;
int dp[N];
struct city {
int s, n;
}cities[N];
int main() {
int n; scanf("%d", &n);
for(int i = 1; i <= n; i++) scanf("%d%d", &cities[i].s, &cities[i].n);
sort(cities, cities + n + 1, [&](city a, city b) { return a.n < b.n;});
for(int i = 1; i <= n; i++) {
dp[i] = 1;
for(int j = 1; j < n; j++) {
if(cities[j].n < cities[i].n) {
dp[i] = max(dp[i], dp[j] + 1);
}
}
}
int res = 0;
for(int i = 1; i <= n; i++) res = max(res, dp[i]);
printf("%d", res);
return 0;
}
for(int i = 1; i <= n; i++) {
dp[i] = a[i];
for(int j = 1; j < i; j++) {
if(dp[i] > dp[j]) {
dp[i] = max(dp[i], dp[j] + a[i]);
}
}
}
数据范围:需要\(O(nlogn)\)
\(1 \leq N \leq 100000\)
\(-10^9 \leq 数列中的数 \leq 10^9\)
贪心策略:尽可能使得每个子序列中的结尾元素越小越好
具体措施:针对每个数,将这个数接到结尾元素最大的小于此元素的子序列后
/*
数组a存储所有数据
数组q[i]表示序列长度为i的子序列的最后一个数
*/
int len = 0;
for(int i = 0; i < n; i++) {
// 找到满足小于a[i]的最大值
int l = 0, r = len;
while(l < r) {
int mid = l + r + 1 >> 1;
if(q[mid] < a[i]) l = mid;
else r = mid - 1;
}
len = max(len, r + 1);
q[r + 1] = a[i];
}
cout << len;
Dilworth定理:对于一个偏序集,最少链划分等于最长反链长度。
Dilworth定理的对偶定理:对于一个偏序集,其最少反链划分数等于其最长链的长度。
以上的铺垫用于解决拦截导弹问题:转化成求最长上升子序列长度
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= m; j++) {
dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);
if(a[i] == b[j]) dp[i][j] = max(dp[i][j], dp[i - 1][j - 1] + 1);
}
}
cout << dp[n][m];
对于包含a[i]的公共上升子序列,将其根据倒数第二个字母是什么进行划分:\
for (int i = 1; i <= n; i ++ ) {
for (int j = 1; j <= n; j ++ ) {
f[i][j] = f[i - 1][j];
if (a[i] == b[j]) {
int maxv = 1;
for (int k = 1; k < j; k ++ )
if (a[i] > b[k])
maxv = max(maxv, f[i - 1][k] + 1);
f[i][j] = max(f[i][j], maxv);
}
}
}
从中发现,每次如果找到公共子序列之后,都要计算一下dp[i][1 ~ j - 1]
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]);
printf("%d\n", res);
标签:排序 最长公共子序列 problem 布局 分析 c++ printf 长度 遍历
原文地址:https://www.cnblogs.com/Hot-machine/p/13246490.html