動態規划:0-1背包問題(使用遞歸方法)


// 最優原則:不管前面的策略如何,此后的決策是是基於當前狀態(由上一次決策產生)的最優決策。
// 當最優決策序列中包含最優決策子序列時,可建立動態規划遞歸方法。
// (有些問題的遞歸式不一定能保證最優原則,因此在求解時有必要對它進行驗證。若不能保持最優原則,則不可應用動態規划方法。)
// 在得到最優解的遞歸式之后,需要執行回溯以構造最優解。
// 缺點:如果不努力地去避免重復計算,遞歸程序的復雜性將非常可觀。
// 方案:如果在遞歸程序中解決了重復計算問題時,復雜性將急劇下降。
// 遞歸方程也可用迭代方程來求解,這很自然地避免了重復計算。迭代方程雖然具有相同的復雜性,不需要附加的遞歸棧空間,因此更快一些。

// 15x1.cpp : Defines the entry point for the console application.

#include "stdafx.h"
#include <iostream.h>
#include <stdlib.h>
#include "dosmax.h"  // has max() and min()

// 動態規划:0-1背包問題(使用遞歸方法)
int p[6] = {0, 6, 3, 5, 4, 6}; // p 價值,多放置一個0,是為了讓下標統一,方便理解和計算。
int w[6] = {0, 2, 2, 6, 5, 4}; // w 重量
// int x[6];
int n = 5;  // 所有物品的數量
int c = 10; // 實際最大總容量

// F函數的返回值是,當前剩為余容量為y,並且當前仍有剩余物品從i到n時,的最優解。
// i為當前檢索到哪個物品的序號
int F(int i, int y)
{
   if (i == n) return (y < w[n]) ? 0 : p[n]; // 最終返回點,一次性比較搞定!
   if (y < w[i]) return F(i+1, y); // 如果y小於當前重量,那么只有一個選擇:繼續向下搜尋,看看能不能放下后面的物品
   // 如果y大於當前物品的重量w[i],就有兩個選擇了(雖然不能當場計算出這兩個選擇的值,但是沒關系,讓它們繼續往下計算就是了):
   // 最后返回(假設當前不放入物品,y的值不變)和(假設當前放入物品,y減去當前物品的重量)的兩種不同選擇之后,所造成不同價值的比較結果。
   // 在i=n之前,所有的F函數代表的臨時總價值,都是懸而未決的。但是一旦i=n之后,依次返回正確的值。
   // F(i+1,y) 和 F(i+1, y-w[i])+p[i],它們都是i+1時候的情況,分頭進行計算,相互不依賴。層次分解,就好象是一顆二叉樹(中間如果y<w[i]就只有一個節點)。
   // 最后只得出一個F的值(最優值),其余F的臨時總價值,全部丟棄。
   return max(F(i+1,y), F(i+1, y-w[i])+p[i]); // 切記,返回的是物品的總價值(最大值=最優解)
}

void main(void)
{
   cout << "Optimal value is ";
   cout << F(1, c) << endl;
}

// =============================dosmax.h=====================================================

#ifndef dosmax_
#define dosmax_

template <class type>
inline type max(type a, type b)
{
   return (a > b)? a : b;
}

template <class type>
inline type min(type a, type b)
{
   return (a < b)? a : b;
}

#endif

// ==================================================================================
// 如果下標從0開始,那么只需要改碰到n的情況,因為沒有w[n]和p[n]存在。但當前w[i]與p[i]不變。
int p[5] = {6, 3, 5, 4, 6}; // p 價值,多放置一個0,是為了讓下標統一,方便理解和計算。
int w[5] = {2, 2, 6, 5, 4}; // w 重量
int n = 5;  // 所有物品的數量
int c = 10; // 實際最大總容量

int F(int i, int y)
{
   if (i == n-1) return (y < w[n-1]) ? 0 : p[n-1]; // cas d'arret,一次性比較搞定!
   if (y < w[i]) return F(i+1, y);
   return max(F(i+1,y), F(i+1, y-w[i])+p[i]);
}

void main(void)
{
   cout << "Optimal value is ";
   cout << F(0, c) << endl;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM