[] Diseño y análisis de dinámica de programación Capítulo IV Algoritmo

La idea básica de la programación dinámica

  • algoritmo de programación dinámica se utiliza comúnmente para resolver problemas con algunas de las mejores propiedades. En estos asuntos, puede haber muchas soluciones factibles. Cada solución corresponde a un valor, esperamos encontrar una solución con valor óptimo.
  • La idea básica es resolver el problema se divide en varias sub-preguntas, la primera resolución de sub-problema, la solución del problema original y la solución obtenida de estos sub-temas.
  • Adecuado sub para resolver problemas de programación dinámica, el problema es a menudo descomponeNo es independiente el uno del otro. Demasiados problemas si el número de niños con un método de dividir y conquistar para resolver este problema, la descomposición de algunos sub-problemas eran de doble contado muchas veces.
  • Si podemos salvar al niño la respuesta al problema ha sido resuelto, y en la necesidad de encontrar las respuestas se han obtenido, por lo que puede evitar un montón de doble contabilidad, ahorrar tiempo. Podemos utilizar una tabla para registrar las respuestas a todos los sub-problemas tienen solución. Ya sea que se utilice en el futuro, independientemente de los sub-problemas, siempre y cuando se calcula que se llenará en la tabla de resultados.

Paso Diseño Programación Dinámica

  1. Propiedades encuentra la solución óptima, y ​​para caracterizar la estructura en la que;
  2. Definido de forma recursiva el valor óptimo (ecuación de programación dinámica escrito);
  3. De manera abajo hacia arriba calcular el valor óptimo;
  4. La información obtenida cuando el cálculo óptimo valor construir una solución óptima.

ps: Pasos 1 a 3 son los pasos básicos del algoritmo de programación dinámica. En el caso de un valor óptimo sólo se requiere, el paso 4 se puede omitir; Para una solución óptima al problema requiere, paso 4 debe ser realizada.

Características problema de programación dinámica

La eficacia de algoritmo de programación dinámica depende de la naturaleza de dos importante del problema en sí tiene:
subestructura óptima:
Cuando la solución óptima contiene solución óptima al problema de su hijo, dijo que el problema tiene estructural por debajo del óptimo.
La superposición de sub-problemas :
cuando un top-down Soluciones algoritmo recursivo, cada sub-problema no siempre se producen nuevos problemas, algunos sub-problemas son de iteraciones. algoritmo de programación dinámica es el uso de la superposición de la naturaleza de esta sub-problemas, la solución sólo una vez para cada sub-problema, y su solución va a guardar una tabla, después de que la solución de estos sub-problemas utilizando tanto como sea posible.

Algunos ejemplos típicos

Un problema de multiplicación de matrices incluso
[Problema]
matriz de n Dada {A1, A2, ..., An }, donde Ai y Ai + 1 es multiplicativa, i = 1,2 ..., n- 1. Cómo determinar el cálculo de la matriz de cálculo, incluso pedir el producto, haciendo que el producto, incluso en este orden de la multiplicación de matrices para calcular el número mínimo requerido?
[Análisis]
El producto matriz incluso AiAi + 1 ... Aj abreviado como A [i: j], donde i≤j; Un cálculo investigó [1: n] calculado orden óptimo.
Se proporciona esta secuencia entre las matrices calculadas Ak y Ak + 1 cadena matriz se rompe, 1≤k <n, el modo correspondiente está completamente entre corchetes (A1A2 ... Ak) (Ak + 1ak + 2 ... An).
Cálculo A: orden óptimo de [1 n] se incluye en la hija Strand calcula matriz A [1: k] y A [k + 1: n] es el mejor orden.
Cálculo: A [1: k] cantidad calculada plus A [k + 1: n] del cálculo, A? [1: k] Plus y A [k + 1: n] se calcula multiplicando la cantidad de
[método]
diseño del estudio a [i: j], 1≤i≤j≤n , más por un pequeño número de veces m [i, j] es necesario, el valor óptimo del problema m original [1, n]
cuando i cuando = j, A [i: j] = Ai, y por lo tanto, m [i, i] = 0, i = 1,2, ..., n
cuando i <j, la
Aquí Insertar imagen Descripción
puede definirse de forma recursiva m [i, j] es :
Aquí Insertar imagen Descripción
[] complejidad del tiempo la ( n 2 ) O (n ^ 2)
[Código]

#include<bits/stdc++.h>
using namespace std;
#define NUM 51
int p[NUM],n;
int m[NUM][NUM];
int s[NUM][NUM];
int main()
{
    cin>>n;
    for(int i=0; i<=n; i++)
        cin>>p[i];
    for(int r=2; r<=n; r++)
        for(int i=1; i<=n-r+1; i++)
        {
            int j=i+r-1;//计算初值,从i处断开
            m[i][j] = m[i+1][j]+p[i-1]*p[i]*p[j];
            s[i][j] = i;
            for(int k=i+1; k<j; k++)
            {
                int t = m[i][k]+m[k+1][j]+p[i-1]*p[k]*p[j];
                if (t < m[i][j])
                {
                    m[i][j] = t;
                    s[i][j] = k;
                }
            }
        }
    cout<<m[1][n]<<endl;
    return 0;
}

algoritmo recursivo:

int Recurve(int i, int j)
{
    if(i==j)
        return 0;
    int u=Recurve(i, i)+Recurve(i+1,j)+p[i-1]*p[i]*p[j];
    s[i][j]=i;
    for(int k=i+1; k<j; k++)
    {
        int t=Recurve(i, k)+Recurve(k+1,j)+p[i-1]*p[k]*p[j];
        if (t<u)
        {
            u=t;
            s[i][j]=k;
        }
    }
    m[i][j]=u;
    return u;
}

Memorando de algoritmos:
algoritmo de programación dinámica como forma memorando a salvar el niño responde preguntas han sido resueltos con una mesa, cuando nos encontramos con que el niño problema, simplemente para encontrar respuestas a los sub-problemas, sin tener que resolver.

int LookupChai  (int i, int j)
{
    if(m[i][j]>0)
        return m[i][j];
    if(i==j)
        return 0;
    int u=LookupChain(i,i)+LookupChain(i+1,j)+p[i-1]*p[i]*p[j];
    s[i][j]=i;
    for(int k=i+1; k<j; k++)
    {
        int t=LookupChain(i,k)+LookupChain(k+1,j)+p[i-1]*p[k]*p[j];
        if (t<u)
        {
            u=t;
            s[i][j]=k;
        }
    }
    m[i][j] = u;
    return u;
}

En segundo lugar, la subsecuencia común más larga
[Problema]
Si una secuencia dada X = {x1, x2, ... , xm}, luego otra secuencia Z = {z1, z2, ... , zk}, X es una subsecuencia se refiere a la presencia el subíndice una secuencia estrictamente creciente {i1, i2, ..., ik } tal que para todo j = 1,2, ..., k tiene: zj = xij.
Dadas dos secuencias X e Y, Z cuando la subsecuencia otra secuencia de ambos X e Y es una subsecuencia de tiempo, dijo Z es una secuencia de X e Y subsecuencia común .
Dadas dos secuencias X = {x1, x2, ... , xm} e Y = {y1, y2, ... , yn}, para encontrar la subsecuencia común más larga de X e Y son. Y la salida de esta secuencia.
[Análisis]
Reset de secuencia X = {x1, x2, ... , xm} y Y = {y1, y2, ... , yn} es la más larga subsecuencia común Z = {z1, z2, ... , zk}, a continuación,
1) Si XM = YN, a continuación, zk = xm = YN, y ZK-1 XM-1 es la más larga subsecuencia común sum in-1.
2) Si xm ≠ yn y zk ≠ xm, entonces Z es la más larga subsecuencia común xm-1 y Y.
3) Si xm ≠ yn y zk ≠ yn, entonces Z y X yn-1 es la subsecuencia común más larga.
A saber:
Aquí Insertar imagen Descripción
[Código]

#include<bits/stdc++.h>
using namespace std;
int n,m;
char a[10010],b[10010];
int dp[10010][10010],x[10010][10010];
vector<char>v;

void LCS(int i,int j)
{
    if(i==0||j==0)
        return;
    if(x[i][j]==1)
    {
        LCS(i-1,j-1);
        v.push_back(a[i]);
    }
    else if (x[i][j]==2)
        LCS(i-1,j);
    else
        LCS(i,j-1);
}

int main()
{
    cin>>n>>m;
    for(int i=1; i<=n; i++)
        cin>>a[i];
    for(int i=1; i<=m; i++)
        cin>>b[i];
    for(int i=1; i<=n; i++)
    {
        for(int j=1; j<=m; j++)
        {
            if(a[i]==b[j])
            {
                dp[i][j]=dp[i-1][j-1]+1;
                x[i][j]=1;
            }
            else if (dp[i-1][j]>=dp[i][j-1])
            {
                dp[i][j]=dp[i-1][j];
                x[i][j]=2;
            }
            else
            {
                dp[i][j]=dp[i][j-1];
                x[i][j]=3;
            }
        }
    }
    cout<<dp[n][m]<<endl;
    LCS(n,m);
    for(int i=v.size()-1;i>=0;i--)
        cout<<v[i]<<" ";
    cout<<endl;
    return 0;
}

En tercer lugar, el sub-segmento y el máximo
[problemas]
a una secuencia determinada por la a1 n enteros (que comprende los números enteros negativos) que consiste en, a2, ..., an, seleccionando el valor máximo y la secuencia de los subsegmentos.
Definir su mayor subsegmento cuando todos son números enteros negativos y cero.
Los valores óptimos requeridos:
Aquí Insertar imagen Descripción
[Análisis]
bj es la mayor posición de sub-segmento y j a 1:
Aquí Insertar imagen Descripción
fácil saber definido por bj, si bj-1> 0 cuando bj = bj-1 + aj, de lo contrario bj = aj.
Bj se calcula la recursión de programación dinámica: bj = max {bj-1 + aj, aj}, 1≤j≤n.

[Código]

#include<bits/stdc++.h>
using namespace std;

int n,a[100010];
int b,sum,l,r,s;

int main()
{
    cin>>n;
    for(int i=1; i<=n; i++)
        cin>>a[i];
    for(int i=1; i<=n; i++)
    {
        if(b>0)
            b+=a[i];
        else{
            b=a[i];
            s=i;
        }
        if(b>sum)
        {
            sum=b;
            r=i;
            l=s;
        }
    }
    cout<<l<<" "<<r<<" "<<sum<<endl;
    return 0;
}

En cuarto lugar, el problema 0-1 mochila
[Problema]
Dado un conjunto de elementos s = {1,2,3, ..., n }, el peso del artículo i es wi, el valor es vi, la capacidad de la mochila de W, es decir, la carga máxima un peso de no más de W. Dentro de un peso total W limitada, cómo elegimos artículos con el fin de hacer que el valor máximo total de los artículos.
Si el artículo no puede ser dividida, es decir, ya sea el artículo entero i para seleccionar o no seleccionar; artículo i en una bolsa no puede ser repetidamente, sólo una parte del artículo no se puede cargar con i, entonces el problema se llama 0-1 problema de la mochila.
Si el artículo puede ser dividida, entonces el problema se llama problema de la mochila, algoritmo voraz adecuado para su uso.
[Análisis]
i≤k≤n valor óptimo de p (i, j).
Mochila capacidad j, es un elemento opcional i, i + 1, ..., n el valor óptimo cuando el problema 0-1 mochila.
Aquí Insertar imagen Descripción
Aquí Insertar imagen Descripción
Aquí Insertar imagen Descripción
[Código]

#include<bits/stdc++.h>
using namespace std;
int n,m;
int f[100010],w[100010],v[100010];
int main()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++)
        cin>>w[i]>>v[i];
    memset(f,0,sizeof(f));
    f[0]=0;
    for(int i=1; i<=n; i++)
        for(int j=m; j>=w[i]; j--)
            f[j]=max(f[j],f[j-w[i]]+v[i]);
    int ans=0;
    for(int j=0; j<=m; j++)
        ans=max(ans,f[j]);
    cout<<ans<<endl;
    return 0;
}
Publicados 335 artículos originales · ganado elogios 110 · Vistas a 20000 +

Supongo que te gusta

Origin blog.csdn.net/weixin_43460224/article/details/105095233
Recomendado
Clasificación