zoukankan      html  css  js  c++  java
  • 浅谈从搜索到动归

    浅谈从搜索到动归

    搜索

    搜索的思路其实就是暴力破解(枚举每种可能的情况)
    一般用dfs的相对较多,dfs是递归的代码结构,简洁明了,思路清晰
    搜索的时候会形成一颗搜索树,整个搜索过程相当于在遍历这个搜索树

    搜索树可通过剪枝来优化,可以理解为把这棵树上多余的枝叶剪去,更快的找到所需的答案

    这里依然以01背包为例

    题目概述:在n件物品取出若干件放在空间为c的背包里,每件物品的体积为w1 w2...wn,与之相对应的价值为v1 v2...vn,最终使背包所装物品的总价值最高

    用普通的搜索来写,就是在选取每个物品的时候,有两种选择 拿or不拿
    时间复杂度为O(2^n)

    int w[105],v[105];
    int n,c,res=0;
    void dfs(int idx,int c,int val){
        if(c<0) return;
        if(idx==n){
            res=max(res,val);
            return;
        }
        dfs(idx+1,c-w[idx],val+v[idx]); //拿这个物品
        dfs(idx+1,c,val); //不拿这个物品
    }
    int main(){
        cin>>c>>n;
        for(int i=0;i<n;++i) cin>>w[i]>>v[i];
        dfs(0,c,0);
        cout<<res;
        return 0;
    }
    

    记忆化搜索

    搜索过程中,往往包含着很多重复的计算
    dfs递归参数中相同的idx和c,返回值一样,这样可以通过一个二维数组来记录
    遇到相同的idx和c时,直接返回记忆化数组中之前算好的值即可

    这里多啰嗦解释两句
    相同的idx和c指的是,不论前面的idx-1件物品是怎么取的,只要取到第idx件物品时,此时背包容量为c,那么从这里开始的dfs返回结果都一样

    int w[105],v[105];
    int mem[105][1005]; //记忆化数组
    int n,c,res=0;
    int dfs(int idx,int c){
        if(mem[idx][c]!=-1) return mem[idx][c]; //之前已经算好了,直接返回
        if(idx==n) return mem[idx][c]=0;
        int t1=0,t2=0;
        if(c>=w[idx]) t1=dfs(idx+1,c-w[idx])+v[idx]; //拿这个物品
        t2=dfs(idx+1,c); //不拿这个物品
        return mem[idx][c]=max(t1,t2);
    }
    int main(){
        cin>>c>>n;
        for(int i=0;i<n;++i) cin>>w[i]>>v[i];
        memset(mem,-1,sizeof(mem));
        cout<<dfs(0,c);
        return 0;
    }
    

    动态规划

    动态规划关键是在于:状态转移
    从一个已求解的状态转移到一个新的状态,从而把所有情况的状态都推出来

    记忆化搜索是建立一个记忆化数组存储dfs递归函数不同参数的返回值
    而动态规划也是建立一个状态转移数组存储已求解的状态
    int dfs(int idx, int c) 中的参数idx和c 对应着 dp[i][j] 中的数组下标i和j
    动态规划和记忆化搜索如此相似,有着异曲同工之妙

    此时时间复杂度已经下降到O(n*m),相比于之前的O(2^n)是一个质的飞跃(n是物品数量,m是背包容量)

    int n,c;
    int w[105],v[105];
    int dp[105][1005]; //dp[i][j] 表示取到第i个物品时,背包容量为j
    int main(){
        cin>>c>>n;
        for(int i=1;i<=n;++i) cin>>w[i]>>v[i];
        for(int i=1;i<=n;++i)
            for(int j=1;j<=c;++j){
                if(w[i]>j) dp[i][j]=dp[i-1][j];
                else dp[i][j]=max(dp[i-1][j],dp[i-1][j-w[i]]+v[i]);
            }
        cout<<dp[n][c];
        return 0;
    }
    
  • 相关阅读:
    浏览器市场份额
    GDB gdb 调试
    tcp基础
    TCP加速方式
    windows10 CTCP
    大延时情况tcp和udp测试
    XAMPP与ISS在80端口冲突问题
    space transport protocols
    win10电脑搭建网站
    如何让nginx显示文件夹目录
  • 原文地址:https://www.cnblogs.com/lidasu/p/10995418.html
Copyright © 2011-2022 走看看