上面的**中寫了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 選擇一種物品時必須付出兩種代價 ...