动态规划-背包问题降维

写在最前面, 这些方法肯定不是我原创的,也是看的别人的思路,
然后自己理解并且实现了
https://blog.csdn.net/iihtd/article/details/51611810?utm_source=blogxgwz2
这个里面讲了背包问题,以及背包的衍生问题,还是不错的,
https://blog.csdn.net/stack_queue/article/details/53544109
这个是著名的背包九讲,讲的很好

0-1 背包问题:

0-1 背包问题解决的是物品只能够选择1次要不就不选,在背包能够装得下的前提下面,能够保证装的价值最大:
状态转移方程 f[i][j] = max{ f[i-1][j] , f[i-1][j - wi] +vi }; 0≤j - wi≤j
用二维的空间来表示是比较简单的
一维表示:f[v] 表示 f[i][v] , 那么由于上面的这个公式: f[i][j] = max{ f[i-1][j] , f[i-1][j - wi] +vi };
可以发现f[i][j] 的值只是和f[j-1][j] , 和f[i-1][j-wi] ,如果我们写出如下的代码:

for(int i = 0 ; i < n ; i++){
        for(int j = m ; j >=0  ; j--){
        vec[j] = max(vec[j] , vec[j-w[i]]+v[i] );
        }
     }

那么对于i = N 的情况,我们计算 vec [j] 时, 由于j-wi < j ,那么vec[j-w[i]]的值会在vec[j]后参与计算,所以,在计算vec[j ] 的时候,我们先读取到的vec[j] 实际上是vec[N-1][j] , 读取到的 vec[j-w[i]]实际上是vec[N-1][j-w[i]],所以可以用上面的公式进行简化。

现在是0-1背包问题的二维代码实现:

/** 
int[] w 表示物品的重量数组
int[] v 表示物品的价值
int weight 表示背包能够装入的重量
*/
public static int backpack01(int[] w, int[] v, int weight) {
        int n = w.length + 1;  //多少个物品
        int[][] temp = new int[n][weight + 1];
        for (int i = 0; i < n; i++) {
            temp[i][0] = 0;//代表背包承受0重量时,背包的价值
        }
        for (int j = 0; j < weight + 1; j++) {
            temp[0][j] = 0;//代表背包存放0个物品时,背包的价值
        }
        for (int i = 1; i < n; i++) {
            for (int j = 1; j < weight + 1; j++) {
                if (j > w[i]) {  //这样背包才能放下这个物品
                    temp[i][j] = Math.max(temp[i - 1][j], temp[i - 1][j - w[i]] + v[i]);
                } else {
                    temp[i][j] = temp[i - 1][j];
                }
            }
        }
        return temp[n-1][weight];
    }

现在是0-1背包问题的一维代码实现
当只有第一个物品的时候,相当于是往背包里面装第一个东西,
第二遍是有两个物品的时候了,相当于在有第一个物品的基础上,
放第二个物品来使背包价值最大化

/** 
int[] w 表示物品的重量数组
int[] v 表示物品的价值
int weight 表示背包能够装入的重量
*/
    public static int backpack01youhua(int[] w, int[] v, int weight) {
        int[] f = new int[weight + 1];
        for (int i = 0; i < v.length; i++) {
            for (int j = weight; j >= w[i]; j--) {
                f[j] = Math.max(f[j], f[j - w[i]] + v[i]);
            }
        }
        return f[weight];
    }

完全背包问题

完全背包问题中每个物品都可以选择无限多次
for (int j = 0; j <=weight; j++)
所以这个地方不同于01背包从背包里面扔东西,
这个是往背包里面一步一步的加

/** 
int[] w 表示物品的重量数组
int[] v 表示物品的价值
int weight 表示背包能够装入的重量
*/
    public static int completebackpack(int[] w, int[] v, int weight) {
        int[] f = new int[weight + 1];
        for (int i = 0; i < v.length; i++) {
            for (int j = 0; j <=weight; j++) {
                f[j] = Math.max(f[j], f[j - w[i]] + v[i]);
            }
        }
        return f[weight];
    }

多重背包问题

部分物品的数量有限,那就和01背包问题一样

/** 
int[] w 表示物品的重量数组
int[] v 表示物品的价值
int[] num 表示每个物品的数量
int weight 表示背包能够装入的重量
*/
      public static int completebackpack(int[] w, int[] v, int[] num, int weight) {
        int[] f = new int[weight + 1];
        for (int i = 0; i < v.length; i++) {
            for (int j = weight; j >= w[i]; j--) {
                for (int k = 1; k <= num[i]; k++) {
                    if (j - k * w[i] > 0 && f[j - k * w[i]] + k * w[i] > f[j]) {
                        f[j] = f[j - k * w[i]] + k * w[i];
                    }
                }
            }
        }
        return f[weight];
    }

背包衍生问题: 硬币凑整数 即子集合加总问题

硬币问题和完全背包问题类似,原题是这样的:有1分,2分,5分,10分四种硬币,每种硬币数量无限,给定n分钱,有多少中组合可以组成n分钱?
采用动态规划的思路,f(i,j)表示的是可以取的0,1,2...i种硬币的情况下,凑够j元一共有多少种方法.递推公式以及相应的一维如何推导为二维如下:


image.png
/**
int[] coins 代表有多少种类型的coin
int target 代表要凑成的数目
*/
public static int coins(int[] coins, int target) {
        int n = coins.length;
        int[] f = new int[target + 1];
        f[0] = 1;
        for (int i = 0; i < n; i++) {
            for (int j = 0; j <= target; j++) {
                f[j] = f[j] + f[j - coins[i]];
            }

        }
        return f[target];
    }

附加一个衍生问题
https://www.cnblogs.com/wudongyang/p/4949557.html
0-1背包问题与子集合加总问题的近似算法
组合总和IIIhttps://blog.csdn.net/wjoker/article/details/84404478

输入两个整数值n和m,求出整数1到n之间的和为m的所有组合
https://blog.csdn.net/qq_36653505/article/details/82634774 python版本简单, java版本麻烦一些
https://blog.csdn.net/weixin_37365120/article/details/70068214

给定一个数组,从中查找是否存在两个数的和等于一个给定的x
另外借鉴了人家一种o(n)的方法,借用一个容器,在容器中查找x-arr[n]的值是否存在,存在就返回 true,不存在将这个值加入容器。
https://blog.csdn.net/chen3749102/article/details/45336371
public static boolean hasAB(int[] arr, int x){
HashSet<Integer> set=new HashSet<>();
for(int i=0;i<arr.length;i++){
if(set.contains(x-arr[i]))
return true;
else
set.add(arr[i]);
}
return false;

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,332评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,508评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,812评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,607评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,728评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,919评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,071评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,802评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,256评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,576评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,712评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,389评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,032评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,798评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,026评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,473评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,606评论 2 350

推荐阅读更多精彩内容

  • 回溯算法 回溯法:也称为试探法,它并不考虑问题规模的大小,而是从问题的最明显的最小规模开始逐步求解出可能的答案,并...
    fredal阅读 13,632评论 0 89
  • 在C语言中,五种基本数据类型存储空间长度的排列顺序是: A)char B)char=int<=float C)ch...
    夏天再来阅读 3,339评论 0 2
  • 树形动态规划,顾名思义就是树+DP,先分别回顾一下基本内容吧:动态规划:问题可以分解成若干相互联系的阶段,在每一个...
    Mr_chong阅读 1,477评论 0 2
  • 从凌晨到响午 逆着时光 我枯坐你塌旁 你向我密语忧思恐惧 我带你听一宿梵音 你问我,为何总是要盯着你的眼睛 我说,...
    哈746阅读 490评论 2 6
  • 星期五晚上,我背着一个大包下了地铁,乘了四个多小时的车子,感觉又累又饿,实在背不动了。我忙打电话给儿子,向儿子...
    夏静波19阅读 228评论 1 5