[] Algorithm design and analysis of dynamic programming Chapter IV

The basic idea of ​​dynamic programming

  • Dynamic programming algorithm is commonly used to solve problems with some of the best properties. In such matters, there may be many feasible solutions. Each solution corresponds to a value, we hope to find a solution with optimum value.
  • The basic idea is to solve the problem will be broken down into several sub-questions, the first sub-problem solving, solution of the original problem and the solution obtained from these sub-issues.
  • Suitable for solving dynamic programming problems, the problem is often decomposed subNot independent of each other. Too many problems if the number of children with a divide and conquer method to solve this problem, the decomposition of some sub-problems were double-counted many times.
  • If we can save the child the answer to the problem has been resolved, and in the need to find out the answers have been obtained, so you can avoid a lot of double counting, save time. We can use a table to record the answers to all sub-problems have solution. Whether being used in the future regardless of the sub-problems, as long as it is calculated that it will fill in the results table.

Step Design Dynamic Programming

  1. Properties find the optimal solution, and to characterize the structure wherein;
  2. Defined recursively the optimal value (dynamic programming equation written);
  3. In a bottom-up fashion calculate the optimal value;
  4. The information obtained when the optimum value calculation construct an optimal solution.

ps: Steps 1 to 3 are the basic steps of the dynamic programming algorithm. In the case of an optimal value only requires, step 4 may be omitted; For an optimal solution to the problem requires, step 4 must be performed.

Features dynamic programming problem

The effectiveness of dynamic programming algorithm depends on two important nature of the problem itself has:
optimal substructure:
When the optimal solution contains optimal solution to the problem of his son, said the problem has structural sub-optimal.
Overlapping sub-problems :
when a top-down recursive algorithm Solutions, each sub-problem are not always produced new problems, some sub-problems are of iterations. Dynamic programming algorithm is the use of the overlapping nature of this sub-problems, the solution only once for each sub-problem, and its solution will save a table, after the solution of these sub-problems using as much as possible.

Some typical examples

A matrix multiplication problem even
[Problem]
Given n matrix {A1, A2, ..., An }, where Ai and Ai + 1 is multiplicative, i = 1,2 ..., n- 1. How to determine the calculation matrix calculation even order the product, making the product even in this order of the matrix multiplication to calculate the required minimum number?
[Analysis]
The matrix product even AiAi + 1 ... Aj abbreviated as A [i: j], i≤j where; A calculation investigated [1: n] calculated optimal order.
This sequence is provided between the calculated matrices Ak and Ak + 1 matrix chain is broken, 1≤k <n, the corresponding mode is completely bracketed (A1A2 ... Ak) (Ak + 1Ak + 2 ... An).
Calculation A: Optimal order of [1 n] is included in the daughter strand calculated matrix A [1: k] and A [k + 1: n] is the best order.
Calculation: A [1: k] calculated amount plus A [k + 1: n] of the calculation, A [1: k] plus? And A [k + 1: n] is calculated by multiplying the amount of
[method]
design Study a [i: j], 1≤i≤j≤n , most by a small number of times m [i, j] required, the optimum value of the original problem m [1, n]
when i when = j, A [i: j] = Ai, and therefore, m [i, i] = 0, i = 1,2, ..., n
when i <j, the
Here Insert Picture Description
can be defined recursively m [i, j] is :
Here Insert Picture Description
[] time complexity THE ( n 2 ) O (n ^ 2)
[Code]

#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;
}

Recursive algorithm:

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;
}

Memorandum of algorithms:
dynamic programming algorithm as memorandum way to save the child answers questions have been resolved with a table, when we encounter the problem child, simply to find answers to the sub-problems, without having to re-solved.

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;
}

Second, the longest common subsequence
[Problem]
If a given sequence X = {x1, x2, ... , xm}, then another sequence Z = {z1, z2, ... , zk}, X is a subsequence refers to the presence the subscript a strictly increasing sequence {i1, i2, ..., ik } such that for all j = 1,2, ..., k have: zj = xij.
Given two sequences X and Y, Z when the sub-sequence another sequence of both X and Y is a subsequence of time, he said Z is a sequence of X and Y common subsequence .
Given two sequences X = {x1, x2, ... , xm} and Y = {y1, y2, ... , yn}, to find the longest common subsequence of X and Y are. And the output of this sequence.
[Analysis]
reset sequence X = {x1, x2, ... , xm} and Y = {y1, y2, ... , yn} is the longest common subsequence Z = {z1, z2, ... , zk}, then
1) If xm = yn, then zk = xm = yn, and zk-1 xm-1 is the longest common subsequence sum yn-1.
2) If xm ≠ yn and zk ≠ xm, then Z is the longest common subsequence xm-1 and Y.
3) If xm ≠ yn and zk ≠ yn, then Z and X yn-1 is the longest common subsequence.
Namely:
Here Insert Picture Description
[Code]

#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;
}

Third, the sub-segment and the maximum
[problems]
to a sequence determined by the n integers a1 (comprising negative integers) consisting of, a2, ..., an, selecting the maximum value and the sequence of sub-segments.
Define its largest sub-segment when all are negative integers and zero.
The required optimal values:
Here Insert Picture Description
[Analysis]
bj is the largest sub-segment position and j to 1:
Here Insert Picture Description
easy to know defined by bj, if bj-1> 0 when bj = bj-1 + aj, otherwise bj = aj.
Bj is calculated dynamic programming recursion: bj = max {bj-1 + aj, aj}, 1≤j≤n.

[Code]

#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;
}

Fourth, the 0-1 knapsack problem
[Problem]
Given a set item s = {1,2,3, ..., n }, the weight of the item i is wi, the value is vi, knapsack capacity of W, i.e., maximum load weighing no more than W. Within a limited total weight W, how we choose items in order to make maximum total value of the items.
If the item can not be split, i.e., either the entire article i to select or not select; i article into a bag can not be repeatedly, only a portion of the article can not be charged with i, then the problem is called 0-1 knapsack problem.
If the item can be split, then the problem is called knapsack problem, greedy algorithm suitable for use.
[Analysis]
i≤k≤n optimum value of p (i, j).
Backpack capacity j, is an optional item i, i + 1, ..., n the optimum value when the 0-1 knapsack problem.
Here Insert Picture Description
Here Insert Picture Description
Here Insert Picture Description
[Code]

#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;
}
Published 335 original articles · won praise 110 · views 20000 +

Guess you like

Origin blog.csdn.net/weixin_43460224/article/details/105095233