A programação dinâmica é tão abstrata assim? (Não seja tolo ao distinguir entre algoritmo recursivo e programação dinâmica) Aprendendo programação dinâmica na postura correta (Introdução)

contente

1. Empurrando uma porta a partir de um algoritmo recursivo puro

 2. Qual é a relação entre programação dinâmica e algoritmo recursivo, e por que a programação dinâmica é um algoritmo recursivo especial?

3. A programação dinâmica continua estudando a definição de estado e transição de estado Percorra o tópico para ver o processo de definição e transição e, a propósito, leve à árvore de estados. . . .

3. Mais alguns exercícios de definição de estado

4. Resumo:

1. Empurrando uma porta a partir de um algoritmo recursivo puro

O processo de processamento de problemas da classe recursiva:

  1. Definição do estado de recursão (núcleo, determina a fórmula de recursão) f[x] : expressão simbólica, mais a definição desta expressão sub 
  2. Determine a fórmula de recorrência (k i-----> k i+1) Determine de qual f[y] f[x] depende
  3. Inicializar init (estado inicial recursivo)
  4. Implementação de programa em loop ou recursivo

Analise o tópico como acima:

70. Subindo escadas

Suponha que você esteja subindo escadas. Você precisa  n de passos para chegar ao topo.

Você pode subir  um 1 ou  2 mais degraus de cada vez. De quantas maneiras diferentes você pode chegar ao topo de um edifício?

  • Definição do estado: dp[i] : o número de maneiras de subir as escadas i
  • Equação de Transição de Estado: Analisando Dependências? Você pode subir 1 ou 2 degraus de cada vez, então, quando estiver nos degraus i, seu último estado pode ser nos degraus i - 1 ou i - 2 degraus na escada. Transferência gráfica:

  •  init : f0] = 1; //Existe apenas um método, não subiu no início, f[1] = 1 sobe do nível 0 para o nível 1
class Solution {
public:
    int climbStairs(int n) {
        int f[n + 1];
        //init:
        f[0] = 1; f[1] = 1;
        for (int i = 2; i <= n; ++i) {
            f[i] = f[i - 1] + f[i - 2];
        }
        return f[n]; 
    }
};

 2. Qual é a relação entre programação dinâmica e algoritmo recursivo, e por que a programação dinâmica é um algoritmo recursivo especial?

 Conforme mostrado na figura acima: A regularização dinâmica deve ser um problema recursivo, mas um problema recursivo não é necessariamente uma programação dinâmica

  • A programação dinâmica é um problema de tomada de decisão.... É um algoritmo recursivo especial para tomar decisões ótimas em um estado....
  • Aqui, vamos começar com uma análise do problema recursivo acima e um tópico semelhante.

746. Suba escadas com custo mínimo

Você recebe uma matriz de inteiros  cost , onde  cost[i] é  i o custo para subir o primeiro degrau da escada. Depois de pagar essa taxa, você pode optar por subir um ou dois degraus.

Você pode optar por   começar a subir as escadas a partir dos degraus subscritos 0 ou subscritos  .1

Por favor, calcule e devolva o custo mínimo para chegar ao topo das escadas.

  • Acontece que a programação dinâmica é um problema especial de recursão. Naturalmente, deve haver uma definição de estado. A definição de estado é o núcleo da resolução de programação dinâmica. Uma definição de estado bem definida tornará a equação de transição de estado da programação dinâmica muito mais simples. .. (mais tarde A sequência explicará um por um)
  • Definir estado: dp[i] : custo mínimo para subir i degraus
  • Análise de transição de estado: 
  • inicial: dp[0] = 0; dp[1] = 0; iniciar escadas, sem custo:
    class Solution {
    public:
        int minCostClimbingStairs(vector<int>& cost) {
            int n = cost.size();
            int dp[n + 1];
            //init 
            dp[0] = 0; dp[1] = 0;
            for (int i = 2; i <= n; ++i) {
                dp[i] = min(dp[i - 1] + cost[i - 1], dp[i - 2] + cost[i - 2]);
                //决策
            }
            return dp[n];
        }
    };

Para resumir a análise da rotina de programação dinâmica:

  • Definição de estado: expressão simbólica dp[i], mais explicação de significado
  • A equação de transição de estado é determinada. (Processo de decisão de estado) A decisão é ótima
  • init: inicializa o estado inicial
  • Indução matemática para julgar se a equação de transferência está correta (iniciante sem gosto, útil para especialistas, verifique)

3. A programação dinâmica continua estudando a definição de estado e transição de estado Percorra o tópico para ver o processo de definição e transição e, a propósito, leve à árvore de estados. . . .

A espada refere-se à Oferta II 100. Soma dos menores caminhos em um triângulo

Dado um triângulo  triangle , encontre a soma mínima do caminho de cima para baixo.

Cada etapa só pode se mover para nós adjacentes na próxima linha. Nós adjacentes  aqui se referem a  dois nós cujo subscrito é igual ao subscrito do nó na camada anterior ou  igual   ao  subscrito do nó na camada anterior + 1  . Ou seja, se você estiver no subscrito da linha atual   , a próxima etapa poderá passar para o subscrito   ou  da próxima linha  .iii + 1

  • Ideias gráficas:
  •  init : dp[0][0] = custo[0][0];
  • 转移方程 :   dp[i][j] = min(dp[i - 1][j] + custo[i][j], dp[i - 1][j - 1] + custo[i][j] );
    class Solution {
    public:
        int minimumTotal(vector<vector<int>>& cost) {
            int n = cost.size();
            int dp[n][n];
            //init
            dp[0][0] = cost[0][0];
            for (int i = 1; i < n; ++i) {       //行
                for (int j = 0; j <= i; ++j) {
                    if (j == 0) dp[i][j] = dp[i - 1][j] + cost[i][j];
                    else if (j == i) dp[i][j] = dp[i - 1][j - 1]  + cost[i][j];
                    else {
                        dp[i][j] = min(dp[i - 1][j], dp[i - 1][j - 1] ) + cost[i][j]; 
                        //状态抉择
                    }             
                }
            }
            int ans = 0x3f3f3f3f;
            for (int i = 0; i < n; ++i) {   
                ans = min(ans, dp[n - 1][i]);       //从最下面一层中抉择结果
            }
            return ans;
        }
    };

    Estado Redefinido: Dê uma olhada nas vantagens da definição de estado:

  • dp[i][j] : a soma das distâncias mais curtas da camada inferior ao ponto (i, j)

  • init : dp[n - 1][i] : todos os pontos na camada inferior

  • Equação de transição: dp[i][j] = min(dp[i + 1][j], dp[i + 1][j + 1]) + custo[i][j];

  • Resumo das vantagens das definições acima: Na definição de reverso, o comprimento da estrada é o mesmo para frente e ré, mas o julgamento de casos especiais é excluído.           

    class Solution {
    public:
        int minimumTotal(vector<vector<int>>& cost) {
            int n = cost.size();
            int dp[n][n];
            //init
            for (int i = 0; i < n; ++i) {
                dp[n - 1][i] = cost[n - 1][i];
            }
            for (int i = n - 2; i >= 0; --i) {
                for (int j = 0; j <= i; ++j) {
                    dp[i][j] = min(dp[i + 1][j], dp[i + 1][j + 1]) + cost[i][j];
                }
            }
            return dp[0][0];
        }
    };

3. Mais alguns exercícios de definição de estado

198. Roubo

Você é um ladrão profissional planejando roubar casas ao longo da rua. Há uma certa quantia de dinheiro escondida em cada quarto. A única restrição que afeta seu roubo é que as casas adjacentes estão equipadas com sistemas antifurto interligados. Se duas casas adjacentes forem arrombadas por ladrões na mesma noite, o sistema alarme automaticamente .

Dada uma matriz de inteiros não negativos representando a quantidade armazenada em cada casa, calcule a quantidade máxima que você pode roubar durante a noite  sem acionar o alarme  .

  • Definição do estado: dp[i] : A quantidade máxima de dinheiro que pode ser roubada roubando a casa anterior sem roubar materiais adjacentes
  • A definição do estado acima está correta????? Existe falta de informação????? Existe também uma restrição de que materiais adjacentes não podem ser roubados. Portanto, roubar a i-ésima sala e não roubar a i-th quarto são dois estados. . . . (chave principal de definição de estado 2: inclua todos os estados)    
  • dp[i][j] (j = 0 ou 1 ): dp[i][0] : representa a quantidade máxima que pode ser obtida sem roubar a i-ésima sala, dp[i][1] : representa roubar a i-ésima sala Quantidade máxima que pode ser obtida
  • Transição de estado: dp[i][0] = max(dp[i - 1][1], dp[i - 1][0]); você pode roubar a i - 1ª casa sem roubar a ith casa, (Nota : sim você pode)               
  • dp[i][1] = dp[i - 1][0] + nums[i - 1] O valor máximo para roubar a i-ésima casa, que só pode ser transferida de dp[i - 1][0] , porque roubando Se a ª casa for encontrada, então a ª - 1ª casa deve estar em um estado que não tenha sido roubado (as casas consecutivas não podem ser roubadas ao mesmo tempo, e a polícia será chamada)
class Solution {
public:
    int rob(vector<int>& nums) {
        //状态定义:  还是思考最重要的问题??  状态如何定义?????
        //  dp[i] ????  足够吗??  我们尝试一下定义: 前i家物资  最后第i 家偷盗的最大偷盗金额??
        //  好像不够呀:  因为 这个转移可能是从 前面的  i - 1 不偷转移过来. 也可以是 i - 1偷转移过来. 这样一分析:  中间还需要保存 不偷的结果呀:
        //所以这样一想还是需要二维的定义:
        //dp[i][0] dp[i][1]  就是前面的i个房间  第 i 个房间 不偷和偷的最大偷盗金额
        int n = nums.size();
        int dp[n + 1][2];
        dp[0][0] = dp[0][1] = 0;            //没有房间一定是0结果 init
        for (int i = 1; i <= n; ++i) {
            dp[i][0] = max(dp[i - 1][1], dp[i - 1][0]);
            dp[i][1] = dp[i - 1][0] + nums[i - 1]; //只能是前一个房子不偷
        } 
        return max(dp[n][0], dp[n][1]);
    }
};

53. Máximo de sub-matrizes e oferta da espada II 091. Pinte a casa

Se houver uma fileira de casas  n e cada casa puder ser pintada em uma das três cores, vermelho, azul ou verde, você precisará pintar todas as casas e certificar-se de que as duas casas adjacentes não podem ser da mesma cor.

Claro, porque os preços das diferentes cores de tinta no mercado são diferentes, o custo de pintar a casa em cores diferentes também é diferente. O custo de pintar cada casa de uma cor diferente é representado por uma  n x 3 matriz de inteiros positivos  costs .

Por exemplo, costs[0][0] representa o custo de pintar a casa 0 de vermelho; costs[1][2] representa o custo de pintar a casa 1 de verde e assim por diante.

Por favor, calcule o custo mínimo para pintar todas as casas.

  • Definição de estado: Igual à pergunta anterior, a chave principal é que a definição de estado precisa incluir todas as situações, e cores diferentes são estados diferentes, portanto, é necessária uma matriz bidimensional e a segunda dimensão identifica a cor
  •  dp[i][j] (j = 0, 1, 2) : ou seja, o custo mínimo de tingir a primeira i casa e a última i casa com a cor j
  • Transferência de estado: a chave central, a última cor i tingida i - 1 não pode ser tingida, então dp[i][j] depende do dp[i - 1][k] anterior ( k != j)

O acima ainda é relativamente abstrato e, em seguida, é fácil de entender observando o código:

class Solution {
public:
    int minCost(vector<vector<int>>& costs) {
        //定义状态: dp[i][j] : 前 i 个房子 最后一个粉刷 j 颜色的最小花费
        //依赖关系:   dp[i][j]----> dp[i - 1][k]   k != j 
        int n = costs.size();
        int dp[n + 1][3];
        for (int i = 0; i < 3; ++i) {               //init没有一栋屋子染色
            dp[0][i] = 0;
        } 
        for (int i = 1; i <= n; ++i) {              //枚举屋子进行状态决策
            dp[i][0] = min(dp[i - 1][1] + costs[i - 1][1],
                         dp[i - 1][2] + costs[i - 1][2]);
            dp[i][1] = min(dp[i - 1][0] + costs[i - 1][0], 
                         dp[i - 1][2] + costs[i - 1][2]);
            dp[i][2] = min(dp[i - 1][1] + costs[i - 1][1], 
                          dp[i - 1][0] + costs[i - 1][0]);
        }
        return min(dp[n][0], min(dp[n][1], dp[n][2]));
    }
};


53. Soma máxima de submatriz   

Insira um array inteiro, um ou mais inteiros consecutivos no array formam um subarray. Encontre o valor máximo da soma de todos os subarranjos.

A complexidade de tempo necessária é O(n).

  • Definição do estado: dp[i] : o valor máximo da soma dos subarrays até o índice i
  • Transição de estado:  contínuo ou desconectado de um novo início ..... (O subarray contínuo é o maior,  desde que o subarray contínuo não tenha se tornado um número negativo, ele pode continuar sendo contínuo , porque pode ser um post -sequence a matriz contínua antes que se torne um número negativo Torne-se maior e forneça contribuição, a menos que < 0 possa ser desconectado, você só pode tornar o todo cada vez menor, )
  • Estado de dependência: dp[i - 1];  
  • Equação de transição de estado: dp[i] = max(dp[i - 1] + nums[i], nums[i]);
class Solution { 
public:
    int maxSubArray(vector<int>& nums) {
        int n = nums.size();
        int dp[n];
        dp[0] = nums[0];//init                          
        int ans = dp[0];
        for (int i = 1; i < n; ++i) {
            dp[i] = max(dp[i - 1] + nums[i], nums[i]);//状态抉择, 连续或者断开
            ans = max(ans, dp[i]);
        }
        return ans;
    }
};


152. Subarray Máximo do Produto

Dado um array inteiro  nums , encontre o subarray contíguo não vazio com o maior produto no array (o subarray contém pelo menos um número) e retorne o produto correspondente ao subarray.

A resposta para o caso de teste é um  inteiro de 32 bits  .

Um subarray  é uma subsequência contígua de um array.

  • Definição de estado: dp[i][0] e dp[i][1] : respectivamente contêm os produtos mínimo e máximo das sub-matrizes das primeiras i tuplas
  • Análise da equação de transição de estado porque pode haver um número negativo muito pequeno * um número negativo torna todo o produto do subarray contínuo muito grande, então precisamos salvar o maior produto do subarray contínuo e o menor produto do subarray contínuo em todo o processo. O produto de arrays, então um array bidimensional é criado, uma dimensão contém o produto mínimo e a outra contém o produto máximo 
  • Estado de dependência: dp[i][0] e dp[i][1] são ambos dependentes: dp[i - 1][0] dp[i - 1][1] nums[i - 1]
  • Os seguintes valores máximos e mínimos começam em: dp[i - 1][0] * nums[i - 1] , dp[i - 1][1] * nums[i - 1] e nums[i - 1 ] Escolha entre os três,              nums[i - 1] significa desconectar o produto anterior e começar do zero
  • class Solution {
        //至于这个题目:  首先还是状态定义:  
        //首先: 这个题目:  我们首先分析: 存在  一个负数  *   负变的非常大, 所以一定保存两个状态:
        //最小值状态  +  最大值状态:  
        //dp[i][0]  和 dp[i][1] 定义:  前面的i个元素的子数组的最小最大乘积
    public:
        int maxProduct(vector<int>& nums) {
            int n = nums.size();
            int dp[n + 1][2];
            dp[0][0] = 1, dp[0][1] = 1;         //init
            int ans = INT_MIN;
            for (int i = 1; i <= n; ++i) {
                dp[i][0] = min(dp[i - 1][1] * nums[i - 1], dp[i - 1][0] * nums[i - 1]);
                dp[i][0] = min(dp[i][0], nums[i - 1]);  //代表断开
                dp[i][1] = max(dp[i - 1][1] * nums[i - 1], dp[i - 1][0] * nums[i - 1]);
                dp[i][1] = max(dp[i][1], nums[i - 1]);  //代表断开
                ans = max(dp[i][1], ans);               //ans可能是在中间产生
            }
            return ans;                            //最后返回这个最大值就是
        }
    };

4. Resumo:

  • Neste capítulo, distinguindo entre algoritmos recursivos e programação dinâmica, é apresentado que a essência da programação dinâmica é diferente dos algoritmos recursivos. a solução ótima.
  • Então é entender o núcleo do algoritmo de programação dinâmica, definição de estado, esclarecer a definição de estado, sempre reconhecer o significado do estado e, em seguida, obter a equação de transição de estado (tomada de decisão) através do significado do assunto combinado com a definição de estado, e, em seguida, preste atenção ao init e ao limite.
  • A definição do estado deve incluir todos os estados. O título implicará mais ou menos na definição do estado. Se a casa adjacente não puder ser roubada, há dois estados de roubo ou não roubo. Se as casas adjacentes forem tingidas de forma diferente, a cor do a casa é diferente.
  • O próximo capítulo continua a otimização de algoritmos de programação dinâmica, principalmente otimização de espaço, técnicas de compressão de espaço + processamento de três problemas clássicos da mochila, além de questões de pincel

Acho que você gosta

Origin blog.csdn.net/weixin_53695360/article/details/122935816
Recomendado
Clasificación