其實這個問題原題是這樣描述的:
有N個節點,每兩個節點相鄰,每個節點只與2個節點相鄰,因此,N個頂點有N-1條邊。每一條邊上都有權值wi,定義節點i到節點i+1的邊為wi。
求:不相鄰的權值和最大的邊的集合。
對於這個問題可能看起來不是很好處理,把問題更加正常化一些:給出一個數組,求出其中一個子集,使得子集中每個元素在原數組中兩兩都不相鄰並使子集的和最大。
因為不能選擇兩個相鄰的元素,那麼對於第i個元素的選擇的可能性就包含選擇i和不選擇i個元素,至於選與不選其實是和第i-1個元素有直接關係的。
考慮兩種情況:
1> 選擇i,那麼第i-1個元素一定不能選
2> 不選擇i,那麼第i-1個元素是可以選,也可以不選的,這決定於第i-2個元素對i-1的影響。
從這兩種情況中可以看出,如果知道第i-1次被選中和不被選中時前i個元素(元素下標從0開始計算)了最大子集和,那麼我們可以算出選擇i和不選擇i各可以獲得的最大子集和。
那麼我們可以得到一個這樣的公式, 其中DS[i]記錄第i個元素被選中時的前i+1個元素的最大子集和。 NS[i]記錄第i個元素未被選中時的前i+1個元素的最大子集和
DS[i] = NS[i-1]+ data[i];
NS[i] = max(NS[i-1], DS[i-1])
接下來看一下例子,假設現在有一個8個元素的數組:
1 7 4 0 9 4 8 8
那麼 NS數組為:
0 1 7 7 7 16 16 24
DS數組為
1 7 5 7 16 11 24 24
下面是程式的代碼
#include <iostream>#include <string.h>#include <stdlib.h>using namespace std;#define NMax 1000int data[NMax];int table[NMax][2];int GetMaxSubsetSum(int len){memset(table, 0 , sizeof(table));//第0行表示NS,表示該元素未被選中//第一行表示DS,表示該元素被選中table[0][0] = 0;table[0][1] = data[0];//動態規劃 過程for (int i = 1; i < len; ++i){table[i][0] = max(table[i-1][1], table[i-1][0]);table[i][1] = table[i-1][0] + data[i];}//列印原始數組for (int i = 0; i < len; ++i)cout << data[i] <<"\t";cout <<endl;//列印NS數組for (int i = 0; i < len; ++i)cout << table[i][0] <<"\t";cout <<endl;//列印DS數組for (int i = 0; i < len; ++i)cout << table[i][1] <<"\t";cout <<endl;//返回整個數組的最大值return max(table[len-1][0], table[len-1][1]);}int main(){int len; cin >> len;if (len <= 0)return 1;for (int i = 0; i < len ; ++i){data[i] = rand()% 10;}cout << GetMaxSubsetSum(len)<<endl;}