01揹包 分組揹包(一維 二維 搜尋

2021-09-26 06:03:57 字數 4388 閱讀 7922

上面的**中寫了01揹包/分組揹包的一維,二維陣列方法,還有搜尋法以及自己的一些思考。

個人對於網上分組揹包的二維轉移方程覺得還不太完善(或者我自己理解的不太對),而且沒有找到很完全的**~~(可能恰好沒找到)~~ ,所以就自己寫了,有附題目位址,如果想看二維陣列分組揹包,直接拉到最後,前面都是廢話。

不想看原位址的,下面是原文:

洛谷p1048採藥 點這裡

**:

#include

using

namespace std;

int t, m;

int tme, var;

int res[

1005

]; int

main()

}}cout << res[t]

;return0;

}

洛谷p1757通天之分組揹包 點這裡

**:

#include

#include

using

namespace std;

int n, m;

int ai, bi, ci;

int row;

int cc[

105]

;int cap[

105]

[1005];

int var[

105]

[1005];

int d[

1005];

intmain()

for(

int i =

1;i <=row;i++)}

} cout << d[m]

;return0;

}

一維的簡單又快速,但是當時想起了很久前看過的硬幣個數max/min值,覺得和01揹包很像,只是把個數換成無數個->完全揹包,可以用以下這種搜尋寫。

洛谷p1616瘋狂的採藥 點這裡

int t, m;

int vis[

100005];

int d[

100005];

int tme[

10005];

int var[

10005];

intdfs

(int s)

} vis[s]=1

;return d[s];}

intmain()

dfs(t)

; cout << d[t]

;return0;

}

或者也可以用dp:

#include

using

namespace std;

int t, m;

int tme[

10005];

int var[

10005];

int d[

100005];

intmain()

for(

int i =

1;i <= t;i++)}

} cout << d[t]

;return0;

}

好吧,到這裡一切正常,然後我就想用第一種搜尋的方式來寫一下01,結果當然是錯的。

這是我的部分錯誤**,vissub用來標記每種藥材有沒有被選中(原來的想法就是,從這些草藥中選一部分,總重量不超過包的要求,然後來算總價值

int t, m;

int vissum[

1005];

int vissub[

105]

;int tme[

105]

;int var[

105]

;int d[

1005];

intdfs

(int s,

int pos)

} vissum[s]=1

;return d[s]

;}

想了很久也沒想明白,後來才發現,**d[s]用來記錄的是,當包中剩餘重量為s時,能得到的最大價值。**但這麼算,d並不能得到最大價值。

舉個例子,假如有1,2,3,4,5種草藥,最大重量為30,對於d[10]要選擇2,4種才能得到最大價值,但是對最初dfs(30),選擇了1,2,3,繼續往下搜尋的時候到達dfs(10),此時2以及被選擇,故不能再選,所以這麼搜尋下去,不可能得到正確的最大價值。但是對於完全揹包沒有問題,因為每個都是從第一種草藥開始選取。

對於前面這種想法,應該是這麼寫的(但是超時):

int maxres =0;

void

dfs(

int s,

int sum,

int pos)}if

(!ok && maxres < sum)

//ok=0證明不能再往下選取

maxres = sum;

}int

main()

dfs(t,1)

; cout << d[t]

;return0;

}

洛谷p1060 開心的金明 點這裡

#include

using

namespace std;

int n, m;

int res[28]

[30005];

int mon[26]

;int var[26]

;int

main()

for(

int i =

1;i <= m;i++)}

cout << res[m]

[n];

return0;

}

洛谷p1757通天之分組揹包 點這裡

一開始,在網上看到的轉移方程是:(d[i][j]為第i組容量為j,k為第i組第k個。

d[i][j]=max(d[i-1][j],d[i-weight[k]]+value[k])
如果只有這個方程,還不太全面,因為當假設某一組有兩個商品(設重量為10,價值前者20,後者10),當要對這組計算的時候,d[i-1][j]假設已經確定為0,那麼第一次d[i][j]得到20,第二次d[i][j]得到10,大值被覆蓋。所以上面這個方程的毛病就是,沒有與本組的其他值比較。

d[i][j]是針對於一整個組來算的,不是對於某乙個物品算的。所以除了和前一組資料對比,還要和本組自己的資料對比。

所以完整的應該是:

#include

using

namespace std;

struct package res[

105]

[1005];

int row;

int m, n;

int ai, bi, ci;

int cnt[

105]

;int d[

105]

[1005];

bool

cmp(package p1, package p2)

intmain()

//------------------------核心**---------------------------------

for(

int i =

0;i <= row;i++)}

d[i]

[k]=

max(d[i]

[k],d[i -1]

[k])

;//不選可能更優,主要作用還是如果沒有能選擇的物品,那麼保留上一級的值}}

cout << d[row]

[m];

return0;

}

在上面的核心**中,我原來還這麼寫過,但是錯了。

for

(int j=

1;j<=cnt[i]

;j++

) d[i]

[k]=

max(d[i-1]

[k],d[i]

[k])

;}

錯誤的原因是資料毒瘤,假如某一組乙個東西也沒有,那麼

d[i][k]=max(d[i-1][k],d[i][k]);不執行,dij根本不會被更新,其實按照完全版寫的也是更規範的。

好吧,記錄一下乙個簡單演算法中碰到的坑,再次特別感謝@20140408abcd大佬。

揹包衍化 二維01揹包

問題引入 有兩種物品 銷售,每種包裝裡兩種物品各有x,y x,yx,y個,售價為t tt元,共有s ss個 銷售的包裝。現在需要兩種物品n,m n,mn,m個,問如何購買可以滿足需要並且花費最少的錢 狀態轉移 設d i j d i j d i j 表示第 一 二種物品分別買了i,j i,ji,j個的...

揹包問題3 二維揹包和分組揹包

有總體積為v,且最大只能放質量為m mm的揹包中,存在n個物品,體積為v iv i vi 價值為w iw i wi 質量為m im i mi 求怎麼放可以得到最大價值。總體來說就是在01揹包的基礎上為物品新增了乙個重量的屬性,還是比較簡單,可以在我們之前的01揹包的 基礎上加一層迴圈就ok了。並且我...

0 1揹包,完全揹包,多重揹包, 二維費用揹包模板

0 1揹包,完全揹包,多重揹包,二維費用揹包模板 0 1揹包模板 每一件物品只有一件 void bag01 int cost,int weigth hdu 2159 fate 二維費用的揹包問題 有件物品,每一件物品具有兩種不同的費用,擁有這支付兩種的值為v1和v2 選擇一種物品時必須付出兩種代價 ...