回溯法:最大裝載問題(使用遞歸,不做任何優化)


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

#include "stdafx.h"

// 回溯法,解空間分為排列數和子集樹,前者是不同節點順序的排列,后者是一個(0,1,...)的向量子集
// 最大裝載問題,是一個NP問題,目前只計算第一艘船,屬於子集樹
// 有幾個貨物,子集樹就有幾層,當前題目為5層
// 我感覺遞歸還是太過於精巧和經湊,很難挖空心思自己寫出來,多熟悉別人現有的程序是一個好辦法。

#include<iostream.h>

template<class T>
class Loading {
friend GetMaxLoading(T [], T, int);
private:
void Compute(int i);
int n; // 貨箱數量
T *w, // 貨箱重量數組
c, // 第一艘船的容量
cw, // 當前的裝載重量
bestw; // 目前最優裝載重量
};

// 重要特性:在遍歷的時候,就得到了結果。使用全局變量保存了最大裝載值
// 此函數一共只有一處return
// 運算過程:
// 第一、第二層能放下貨物,走的是if語句的條件分支,然后開始計算第三層。
// 第三層因為不滿足if語句條件,直接走的是if語句后面的語句,什么值都不改變。
// 第四、第五層直接走的是if語句后面的語句,什么值都不改變。
// 第六層返回,於是第五、第四、第三都直接返回,相當於第二層的Compute(i+1);語句計算完畢(但第二層整個過程沒有計算完畢,后面還有其它語句)
// 此時,相當於第二層x=1的情況的子樹計算完畢了,但還要在這層繼續計算x=0的子樹。
// 所以把當前cw值恢復成不裝當前貨物時候的值,即程序繼續往下執行cw -= w[i];語句
// 然后相當於,在第二層不裝貨物的情況下,開始遍歷計算第三層的值。等它返回之后,根節點的左子樹計算完畢。
template<class T>
void Loading<T>::Compute(int i)
{
cout << " i= " << i << ", ";
cout << " cw= " << cw << endl;
// if (i==n) cout << endl;

if (i > n) { // 在葉節點
if (cw > bestw) bestw = cw; // 到了葉節點就要判斷,是否得到了比當前最大裝載更大的值
cout << " 終點了!返回!" << endl;
return;
}
// 能放下當前貨箱的重量,繼續深度遍歷,當前最大裝載cw加上當前貨箱的重量
if (cw + w[i] <= c) { // 嘗試 x[i]=1,能裝下當前貨箱的重量
cout << " 放下當前貨箱的重量=" << w[i] << ",准備深度遍歷" << i+1 << "" << endl;
cw += w[i];
Compute(i+1); // 放下了當前貨物之后,就立刻嘗試下一層,直到超出為止。即所謂深度遍歷算法
// 而且瞎試,反正超過了葉節點后會自動返回。
cw -= w[i]; // 下一層返回了,必然是到了最底層(不確定)
}
// 放不下當前貨箱,但繼續深度遍歷,當前最大裝載cw不變
// 放不下的時候,直接就返回了,沒有在Compute(i+1); 的下面再放其它語句
// 放不下當前貨箱的時候,什么都不干、什么都不改變,它自身就等着返回了。
// ,只繼續深度遍歷期待它的子樹能放下一部分東西的時候改變一些東西。
cout << " 放不下,准備深度遍歷" << i+1 << "" << endl;
Compute(i+1); // 嘗試 x[i]=0,放不下當前貨箱的重量。
}

template<class T>
T GetMaxLoading(T w[], T c, int n)
{
Loading<T> X;
X.w = w;
X.c = c;
X.n = n;
X.bestw = 0;
X.cw = 0;

// 計算最佳裝載,從1層算起(很重要)。0層是無用值,放棄。
X.Compute(1);
// 因為是自動遞歸計算,所以返回的時候,已經得到了最大裝載值
// 返回的是全局變量的最大裝載值,不是Compute函數的返回值
return X.bestw;
}

void main(void)
{
int w[6] = {0, 7, 2, 6, 5, 4}; // 5個貨物,w[0]放棄
int n = 5;
int c = 10;
cout << "Value of max loading is" << endl;
cout << GetMaxLoading(w,c,n) << endl;
}


免責聲明!

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



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