/**
动态规划(Dynamic Programming)技术广泛应用于许多组合优化问题中
e.g.
1.Floyd
2.矩阵链的乘法
3.最大效益投资
4.背包问题
5.最长公共子序列问题
6.图像压缩
7.最大子段和
8.最优二分检索树
9.RNA的最有二级结构

关键词:
记忆花搜索

01背包问题
*/

///01背包问题 的 深搜穷竭
#include "cstdio"
#include "algorithm"
#define N 105
int n=4,weight=5;
int w[N]={2,1,3,2},v[N]={3,2,4,2};
int rec(int i,int j)
{
    int res;
    if(i==n)
    {
        res=0;
    }
    else if(j<w[i])///不能放
    {
        res=rec(i+1,j);
    }
    else
    {
        res=std::max(rec(i+1,j),rec(i+1,j-w[i])+v[i]);///放/不放
    }
    return res;
}
int main()
{
    printf("%d\n",rec(0,weight));
}
/**
  搜索深度为n,每层搜索都需要2层分支,Perfect Tree结构,最坏需要O(2^n)
  等比级数复杂度,n较大时,不可取
*/

用数组记忆下重复计算的部分,优化为O(nW)

#include "cstdio"
#include "cstring"
#include "algorithm"
#define N 105
int n=4,weight=5;
int w[N]={2,1,3,2},v[N]={3,2,4,2};
int dp[N+1][N+1];
int rec(int i,int j)
{
    if(dp[i][j]>=0)
    {
        return dp[i][j];
    }
    int res;
    if(i==n)
    {
        res=0;
    }
    else if(j<w[i])
    {
        res=rec(i+1,j);
    }
    else
    {
        res=std::max(rec(i+1,j),rec(i+1,j-w[i])+v[i]);
    }
    return dp[i][j]=res;
}
int main()
{
    memset(dp,-1,sizeof(dp));
    printf("%d\n",rec(0,weight));
}

迭代式(递推式)

#include "cstdio"
#include "cstring"
#include "algorithm"
#define N 105
int n=4,weight=5;
int w[N]={2,1,3,2},v[N]={3,2,4,2};
int dp[N+1][N+1];
void solve()
{
    for(int i=n-1;i>=0;i--)
    {
        for(int j=0;j<=weight;j++)
        {
            if(j<w[i])
            {
                dp[i][j]=dp[i+1][j];
            }
            else
            {
                dp[i][j]=std::max(dp[i+1][j],dp[i+1][j-w[i]]+v[i]);
            }
        }
    }
}
int main()
{
    memset(dp,0,sizeof(dp));
    solve();
    printf("%d",dp[0][weight]);
}

 i的循环正序

for(int i=0;i<=n-1;i++)
    {
        for(int j=0;j<=weight;j++)
        {
            if(j<w[i])
            {
                dp[i+1][j]=dp[i][j];
            }
            else
            {
                dp[i+1][j]=std::max(dp[i][j],dp[i][j-w[i]]+v[i]);///你还剩多少重量
            }
        }
    }

状态转移式 (前i个物品中选取总重不超过j)

for(int i=0;i<=n-1;i++)
    {
        for(int j=0;j<=weight;j++)
        {
            dp[i+1][j]=std::max(dp[i+1][j],dp[i][j]);
            if(j+w[i]<=weight)
            {
                dp[i+1][j+w[i]]=std::max(dp[i+1][j+w[i]],dp[i][j]+v[i]);///你已经放了多少重量
            }
        }
    }

 同一问题可能有各种各样的解决方法

对此题综上:

1.搜索的记忆化(计算过的就记住)

2.递推关系的DP(1.放不下 2.能放下(放与不放哪个合算?)  此状态来自上一行的哪一个容量 具体看书上的图)

3.从状态转移考虑的DP(此状态将转移到下一行的哪一个容量)

 

经典的LCS问题

#include "cstdio"
#include "algorithm"
#define N 1005
int n=4,m=4;
char s[N]="abvd",t[N]="ddsd";
int dp[N+1][N+1];
void solve()
{
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<m;j++)
        {
            if(s[i]==t[j])
            {
                dp[i+1][j+1]=dp[i][j]+1;///找到一个相同的+1
            }
            else
            {
                dp[i+1][j+1]=std::max(dp[i+1][j],dp[i][j+1]);///否则往前走
            }
        }
    }
    printf("%d\n",dp[n][m]);
}
int main()
{
    solve();
}
View Code

相关文章: