【DP经典问题】

来源:互联网 发布:centos www服务器配置 编辑:程序博客网 时间:2024/06/06 02:39

最大连续和:

O(n) 算法: f[n] = max(f[n-1]+a[n], a[n])

O(nlogn) 算法:分治算法,算法竞赛入门经典有介绍

hackerrank给了一个 k-dane 算法:http://blog.csdn.net/joylnwang/article/details/6859677


最大子序列和(不要求连续):f[i]表示 1-i 最大子序列和,用d[i]表示最大子序列的结束位置。。


LIS问题:

nlogn算法: d[i] 保存长度为i的上升子序列的最后一个元素,维护d[i]使得d[i]总是最小。

可以这样理解,对于相同长度的IS,最后一个元素较小的子序列增长的“潜力”较大。

如果需要输出LIS,则 d[i] 保存的是下标,pa[i]保存上一个元素下标。代码见LCS问题。

// poj 2533#include<iostream>#include<cstdio>#include<cstdlib>#include<map>#include<algorithm>#include<vector>#include<queue>#include<cstring>#include<set>#include<list>using namespace std;const int maxn = 1000000;const int inf = 0x7fffffff;int T, n;int a[maxn+5];int d[maxn+5];int main() {#if 0    freopen("input.in", "r", stdin);#endif        scanf("%d",&n);        if (n == 0) {printf("0");return 0;}        for (int i=1;i<=n;++i) scanf("%d", &a[i]);        for (int i=1;i<=n;++i) d[i] = inf;        d[0] = 0;        d[1] = a[1];        for (int i=2;i<=n;++i) {            int *p = lower_bound(d+1, d+n, a[i]);            if (*p > a[i])                 *p = a[i];        }        int ans = 1;        for (int i=n;i>=1;--i)            if (d[i] != inf) {                ans = i;                break;            }        //for (int i=1;i<=n;++i) cout << d[i] << ' ';cout << endl;        printf("%d\n", ans);    return 0;}


LCS问题:

nlogn算法:http://blog.csdn.net/non_cease/article/details/6918848

将LCS转换成LIS来解决,思想也非常容易理解。

#include <cmath>#include <cstdio>#include <vector>#include <iostream>#include <algorithm>#include <map>using namespace std;#define rep(i, s, t) for(int (i)=(s);(i)<=(t);++(i))#define urep(i, s, t) for(int (i)=(s);(i)>=(t);--(i))const int inf  = 0x7fffffff;const int maxn = (int)(1e5);int n, m, len;int a[maxn+5];int b[maxn+5];int d[maxn+5];int pa[maxn+5];vector<int> sav[maxn+5];vector<int> arr; // array to get LISmap<int, int> ha;bool cmp(int lhs, int rhs) {    if (lhs == inf) return false;    if (rhs == inf) return true;    return arr[lhs] < arr[rhs];}int main() {#if 1    freopen("input.in", "r", stdin);#endif    cin >> n >> m;    rep(i, 0, n-1) cin >> a[i];    rep(i, 0, m-1) cin >> b[i];    // map element in a [1-1e9] to [1-1e6], hash_value = position where the element firstly appearanced    // hash_value = ha[origin_value], origin_value = a[hash_value]    rep(i, 0, n-1) {        if (ha.count(a[i]) == 0) {            ha[a[i]] = i;        }    }    // for every distinct element in a, find its appearance in b    urep(i, m-1, 0) {        if (ha.count(b[i])) {            sav[ha[b[i]]].push_back(i);        }    }    rep(i, 0, n-1) {        if (ha.count(a[i])) {            int id = ha[a[i]];            int sz = sav[id].size();            rep(j, 0, sz-1) arr.push_back(sav[id][j]);        }    }    len = min(n, m);    rep(i, 0, len) d[i] = inf;    d[1] = 0;    d[0] = -1;    pa[0] = -1;    int sz = arr.size();    rep(k, 0, sz-2) cout << arr[k] << " ";cout << arr[sz-1] << endl;    rep(k, 1, sz-1) {        int *p = lower_bound(d+1, d+len, k, cmp);        if (cmp(k, *p)) {            pa[k] = *(p-1);            *p = k;        }    }    int idx;    for(idx=len;idx>=1;--idx)        if (d[idx] != inf) break;    vector<int> ans;    int cur = d[idx];    //cout << "length: " << idx << endl;    while (cur != -1) {        ans.push_back(b[arr[cur]]);        cur = pa[cur];    }    sz = ans.size();    rep(i, 0, sz-2) cout << ans[sz-1-i] << " ";cout << ans[0] << endl;    return 0;}



0 0