Jimmy Blog

Welcome!

动态规划一般思路

动态规划一般来说分为线性的和多维的。

通用的方法--记忆化搜索

此类动态规划的关键点是找到“局部最优”,一般是用best[i]代表i之后的局部最优解情况,然后用f(i)自顶向下遍历。 用flag[i]表示是否计算过,若计算过,f(i)直接返回结果(剪枝),若没计算过,则进行计算。
此通用方法思维难度较低,但在绝大部分情况下,时间复杂度都较高,因为其实质是dfs遍历的剪枝,而真正的动态规划解法是wfs的剪枝。 若时间要求不严格,则可以过,但大多数情况下还是过不了的。
典型例题:http://www.luogu.org/problem/show?pid=1280

代码:

#include <iostream>
#include <vector>

using namespace std;

int N, K;

typedef struct Task{
    int p, t;
    Task(int p, int t) :p(p), t(t){};
};

int min(int a, int b){ return a < b ? a : b; }

vector<Task*> tasks;
vector<int> start;
vector<int> best;
vector<bool> is;

int f(int t)
{
    if (t > N) return 0;
    else if (is[t]) return best[t];
    else if (start[t] == -1) return f(t + 1);
    else
    {
        int mint = 0x7fffffff;
        for (int i = start[t]; i < K && tasks[i]->p == t; i++)
            mint = min(mint, f(t + tasks[i]->t) + tasks[i]->t);

        best[t] = mint;
        is[t] = true;
        return mint;
    }
}

int main()
{
    freopen("t.txt", "r", stdin);
    cin >> N >> K;
    start.resize(N + 1, -1);
    best.resize(N + 1, 0);
    is.resize(N + 1, false);
    for (int i = 0; i < K; i++)
    {
        int p, t;
        cin >> p >> t;
        tasks.push_back(new Task(p, t));

        if (start[p] == -1)
            start[p] = i;
    }

    cout << N - f(1);

    return 0;
}

线性动态规划

01背包,完全背包,最大上升子序列等等。

多维动态规划

  1. 双线程dp
  2. 最大子矩阵
  3. 背包问题的变种(先对物品排序)
  4. 双约束条件的背包
comments powered by Disqus