混合揹包與泛化揹包(未完成)

2021-04-20 22:45:37 字數 4138 閱讀 6577

本文作於2023年歲末,沒有寫完就決定2023年不搞oi了。此文暫且存放在這裡,待我有大學上之後,將決定是否開始維護這個部落格。這裡以後將代替林影閣。

混合揹包

揹包是個很經典而實用的問題……

總體上,揹包可以分為4類。部分揹包(可以用貪心有效解決),01揹包,完全揹包,多重揹包(這三個可以用dp有效解決)。而混合揹包是後三者的混合。這幾個的理論在《揹包問題九講》中有過詳細介紹。這裡我們只通過乙個例項來看混合揹包是如何實現的。

例1 期中考試前夜

【問題描述】

快樂的dw今天很不高興,因為明天要期中考試,而且她知道她複習不完了。

【問題描述】

雖然形勢不很樂觀,但dw還是希望明天能拿到盡可能高的分數。

dw簡單分析了一下,現在可利用的時間為m,還有n個任務需要完成。第i個任務需要一定的時間t(i),但也有一定的價值v(i)。

但是好像沒這麼簡單。她發現所有的任務可以分為兩類,a類和b類。

a類是背誦類的任務。如果第i個任務是a類的,那麼第一遍做這個任務獲得價值v(i),再做它的價值就是0。也就是說,第i個任務做x次的價值就是v(i) (x>0)。

b類是練習類的任務。如果第i個任務是b類的,那麼每做一遍這個任務獲得的價值都是v(i)。也就是說,第i個任務做x次的價值就是x*v(i)。

dw希望她能利用這些時間獲得最大的價值,而坐在她後面的zs也在忙著複習(是複習noip,不是期中考試),所以請聰明的你來幫忙了。

【輸入格式】

第一行兩個整數,n,m。含義已述。

接下來有n行,第i+1行有三個量v,t,chr。v,t分別表示v(i),t(i)。chr是字元a或b,表示它所屬的任務類別。

【樣例輸入】

5 10

2 3 a

2 4 a

2 5 a

2 6 a

5 2 b

【輸出格式】

一行,乙個整數,表示可以獲得的最大價值。

【樣例輸出】

25【資料規模】

n<=1000,m<=10000,其它資料<=maxlongint。

可以看出這是01揹包和完全揹包的混合。見**段1。

泛化揹包

揹包中放入的物品可能存在其它限定。比如,要放入物品a,物品b也必須放入。稱這種關係為依附關係。《金明的預算方案》是乙個典例,不過它的依附方式很簡單,對於每一種依附情況列舉即可。

泛化揹包這個概念是由dd牛提出,用來解決更一般的具有依附關係的揹包問題。

例2 金明的預算方案改

【問題描述】

金明今天很開心,家裡購置的新房就要領鑰匙了,新房裡有一間金明自己專用的很寬敞的房間。更讓他高興的是,媽媽昨天對他說:「你的房間需要購買哪些物品,怎麼布置,你說了算,只要不超過n元錢就行」。今天一早,金明就開始做預算了。

物品之間是存在依附關係的,下表就是一些例子:

如果要買一件物品,如果它有父節點,那麼它的父節點也一定要買。比如。要買掃瞄器就必須買電腦,那麼買電腦也就必須買桌子。所有的依附關係都可以由乙個森林來描述,這意味著不可能出現「依附環」。

金明想買的東西很多,肯定會超過媽媽限定的n元。於是,他把每件物品規定了乙個重要度,分為5等:用整數1~5表示,第5等最重要。他還從網際網路上查到了每件物品的**(都是10元的整數倍)。他希望在不超過n元(可以等於n元)的前提下,使每件物品的**與重要度的乘積的總和最大。

設第j件物品的**為v[j],重要度為w[j],共選中了k件物品,編號依次為j1,j2,……,jk,則所求的總和為:v[j1]*w[j1]+v[j2]*w[j2]+ …+v[jk]*w[jk]。(其中*為乘號)請你幫助金明設計乙個滿足要求的購物單。

【輸入格式】

輸入檔案的第1行,為兩個正整數,用乙個空格隔開:

n m

其中n(<32000)表示總錢數,m(<60)為希望購買物品的個數。)

從第2行到第m+1行,第j行給出了編號為j-1的物品的基本資料,每行有3個非負整數

v p q

(其中v表示該物品的**(v<10000),p表示該物品的重要度(1~5),q表示該物品的直接依附物品。如果它沒有依附的物品,那麼q=0)

【樣例輸入】

10500 0 1

5000 1 4

300 1 5

1000 2 2

800 2 4

10 0 1

10 6 3

10 6 2

200 0 3

800 9 3

(注:這個樣例與圖中物品的標記一一對應)

【輸出格式】

輸出檔案只有乙個正整數,為不超過總錢數的物品的**與重要度乘積的總和的最大值

(<200000)。

下面我們來討論這個問題。

請設想,如果你就是那個最優解,你是否真的關心放在揹包中的是哪些物品呢?可能並不是,你所關心(或擔心)的是,備選物品是否利用揹包的空間組合出了最優解。

我們規定節點k由乙個函式fk表示(請將k理解為函式f的下標),fk(w)表示這樣的含義:提供空間w,將以k為根節點的子樹中的節點作為物品選擇物件,組合出的最優價值。

如果要求f1,那麼我們會想知道f2和f3,那麼f1(w)=max,其中0<=k<=w。它的最優子結構很好證明。看吧,我們沒有以物品為物件。這種最優解操作是在函式層面上的。也就是說,為了得到節點p的函式值fp(v),則它的孩子的f值要在這之前獲得。之後我們列舉各種空間分配的方法,找到其中的最大值。

我們就把這些物品「泛化」了,節點2、3通過函式f的形式,將自己這棵自樹的最優解情況匯報給節點1,節點1通過上述的狀態轉移方程,評測出節點1的最優解。

初始化時,所有葉子節點都做這樣的操作。設節點k的價值為v,價錢為w。fk全部賦0,然後fk[w]=v,

在程式實現上,我們要把這個森林轉化成二叉樹,這樣處理起來比較方便(同樣的比如《選課》)。

程式實現見**段2(未完成)。

**段1

program example1(input,output);

varn,m,i:longint;

v,t:array[1..1000]of

longint;

f:array[0..10000]of

longint;

iszeroone:array[1..1000]of

boolean;

chr0,chr1:char;

function max(x,y:longint):longint;

begin

if x>y then exit(x) else exit(y);

end;

procedure zeroonepack(cost,value:longint);

varvi:longint;

begin

for vi:=m downto cost do

f[vi]:=max(f[vi],f[vi-cost]+value);

end;

procedure completepack(cost,value:longint);

varvi:longint;

begin

for vi:=cost to m do

f[vi]:=max(f[vi],f[vi-cost]+value);

end;

begin

assign(input,'a.in'); reset(input);

readln(n,m);

for i:=1

to n do

begin

readln(v[i],t[i],chr0,chr1);

if chr1='a'

then iszeroone[i]:=true

else iszeroone[i]:=false;

end;

fillchar(f,sizeof(f),0);

for i:=1

to n do

if iszeroone[i] then zeroonepack(t[i],v[i])

else completepack(t[i],v[i]);

writeln(f[m]);

close(input);

end.

**段2(未完成)

混合揹包 分組揹包

啥是混合揹包呢,就是包含01揹包,完全揹包,多重揹包。有n件物品,揹包承重最大為m,w i 代表重量,v i 代表價值,s i 代表種類。s i 1,可用1次,s i 0,可用無限次,s i 0,可用s i 次.解法 見 const int maxn 1e4 5 int n,m,dp m 1 w n...

分組揹包,混合揹包,有依賴的揹包

一.分組揹包 每組只能選乙個 所謂分組揹包,就是把物品分成n組,每組裡面m個物品,從這n組中每組選乙個物品,使得在揹包體積是v的條件下價值最大 思路 對於每一組由於只能選乙個,所以就是決策這一組中選哪乙個獲得的價值最大 for int i 1 i n i 列舉這是第幾組 num i 代表第i組物品的...

0 1 完全揹包 多重揹包問題 混合揹包

0 1揹包問題 dp i j 表示前i件物品,體積容量為j的揹包所能獲得的最大價值 決策是第i個物品選不選 轉移方程 dp i j max dp i 1 j dp i 1 j v i w i n為物品數量,m為揹包體積 for int i 1 i n i for int j 0 j m j if j...