日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

背包问题 c语言版

發布時間:2023/12/10 编程问答 40 豆豆
生活随笔 收集整理的這篇文章主要介紹了 背包问题 c语言版 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

?b站背包問題專題講解

背包問題入門看《圖解算法》中9.1“背包問題”章節較好理解

背包問題目錄

  • ==一、01背包問題==
    • 輸入格式
    • 輸出格式
    • 數據范圍
    • 輸入樣例
    • 輸出樣例
  • ==二、完全背包問題==
  • ==三、多重背包問題 1==
    • 輸入樣例
    • 輸出樣例
  • ==四、多重背包問題 2==
    • 數據范圍
  • ==五、多重背包問題 3 終極版== 男人八題之一
    • 數據范圍
  • ==六、混合背包問題==
    • 輸入格式
    • 輸出格式
    • 數據范圍
    • 輸入樣例
    • 輸出樣例:
  • ==七、二維費用背包問題==
    • 輸入格式
    • 輸出格式
    • 數據范圍
    • 輸入樣例
    • 輸出樣例
  • ==八、分組背包問題==
    • 輸入格式
    • 輸出格式
    • 數據范圍
    • 輸入樣例
    • 輸出樣例:

一、01背包問題

有 N 件物品和一個容量是 V 的背包。每件物品只能使用一次

第 i 件物品的體積是vi,價值是 wi

求解將哪些物品裝入背包,可使這些物品的總體積不超過背包容量,且總價值最大。
輸出最大價值。

輸入格式

第一行兩個整數,N,V,用空格隔開,分別表示物品數量和背包容積。

接下來有 N 行,每行兩個整數 vi,wi,用空格隔開,分別表示第 i 件物品的體積和價值。

輸出格式

輸出一個整數,表示最大價值。

數據范圍

0 < N,V ≤ 1000
0 < vi,wi ≤ 1000

輸入樣例

4 5 1 2 2 4 3 4 4 5

輸出樣例

8 #二維動態規劃 f[i][j]表示只看前i個物品,總體積是j的情況下,總價值最大是多少 result = max{f[n][0~V]} f[i][j]: 1.不選第i個物品,f[i][j] = f[i - 1][j] 2.選第i個物品,f[i][j] = f[i - 1][j - v[i]] f[i][j] = max{1,2,} 初始化:f[0][0] = 0; #include<stdio.h> int max(int a,int b){if(a>=b) return a;else return b; } int main(){int N=500;int n,m; //n是物品數,m是背包體積int f[N][N];int v[N],w[N];scanf("%d %d",&n,&m);for(int i=1;i<=n;i++) scanf("%d %d",&v[i],&w[i]);for(int i=1;i<=n;i++)for(int j=0;j<=m;j++){f[i][j] = f[i-1][j];if(j >= v[i])f[i][j] = max(f[i][j], w[i] + f[i-1][j-v[i]]);}printf("%d",f[n][m]);return 0; }

我們發現每次再對新的一行進行計算時,只用到了上一行的信息,那么我們可以嘗試把二維背包變為一維,如下:

int f[N];int v[N],w[N];scanf("%d %d",&n,&m);for(int i=1;i<=n;i++) scanf("%d %d",&v[i],&w[i]);for(int i=1;i<=n;i++)for(int j=m;j>=v[i];j--) //我們每次運用到的上一行的信息都在前面的位置,為了防止覆蓋掉,所以要從大到小f[j] = max(f[j],f[j-v[i]] + w[i]);

?1.不管背包是否裝滿的所有可能中價值最大的,此類問題的二維數組應初始化全部為0。
2.要求背包必須恰好裝滿, 這樣需要把f [ 0 ] [ 0 ~ m] 初始化為0, 其余初始化為負無窮。保證結果一定是從f [0][x]傳遞過來。(0體積的背包)

二、完全背包問題

現在每一個物體都有無限個啦!可以重復選,其余部分與上一題完全相同。

直接一維背包開搞! f[i] 表示總體積為i的情況下,最大價值是多少 result = f [m]

之前的代碼是上面一行傳遞給下面一行,這次是同一行中前一列的最大價值和上面一行的同一列 傳遞給后一個

實現如下:

for(int i = 0;i < n; i++) {for(int j = v[i]; j <= m; j++) //從小到大f[j] = max(f[j], f[j - v[i]] + w[i]); }

三、多重背包問題 1

多了一個條件,第 i 種物品最多有 si

輸入樣例

分別對應 vi,wi ,si

4 5 1 2 3 2 4 1 3 4 3 4 5 2

輸出樣例

10 f[i] 總體積是i的情況下,最大價值是多少for(int i = 0; i < n; i++) {for(int j = m; j >= v[i]; j--)f[j] = max(f[j], f[j-v[i]] + w[i], f[j - 2 * v[i]] + 2 * w[i]...); //到s[i]個 做個循環 } 1. f[i] = 0; 所有初始化為0result = f[m] 2. f[0] = 0; 其余初始化為復無窮 恰好裝滿result = max{f[0...m]}

可以由01背包修改而來,只不過要多一個循環對于每一件物體拿不同數量的比較

#include<stdio.h> int max(int a,int b){if(a>=b) return a;else return b; } int n,m; int f[110]; int main(){scanf("%d %d",&n,&m);for(int i=0 ; i<n ;i++){int v,w,s;scanf("%d%d%d",&v,&w,&s);for(int j=m ; j>=0 ; j--){for(int k=1 ; k<=s && k*v <= j ; k++){f[j] = max(f[j], f[j - k * v] + k * w);}}}printf("%d",f[m]); }

四、多重背包問題 2

數據范圍

0 < N ≤ 1000
0 < V ≤ 2000
0 < vi,wi,si ≤2000

與上一道問題完全一樣,是多重背包的二進制優化方法 ,可以算數量級更大的輸入

可以把每種物體拆開為 s個,從而轉換為01背包問題看, 但數量級還是很大,用二進制拆法

給定任意數x,最少選多少個數,可以拼成<=x 的所有的數呢 ?
答案是 log2(x) 的上取整
eg:
x = 7 選 1,2,4即可表示<=7的所有數字 7 = 1+2+4
x=10 選 1,2,4,3即可

這樣我們就不需要把同一種物體拆稱 si 個,而是拆成log2(si)上取整個物體,復雜度降低

#include<stdio.h> int max(int a,int b){if(a>=b) return a;else return b; } struct GOOD{ //創建物體結構體,用來創建拆出來的新物體 int v,w; }; int f[2010]; int n,m; int main(){struct GOOD goods[100000]; int t = 1; //放入goods結構體數組的計數器 scanf("%d%d",&n,&m);for(int i=0 ; i<n ; i++){int v,w,s;scanf("%d%d%d",&v,&w,&s);for(int k=1 ; k<=s ; k*=2){s -= k;goods[t].v = v*k;goods[t].w = w*k;t ++; }if(s>0) { //用來對應 10被分為 1,2,4,3的1情況 goods[t].v = v*s;goods[t].w = w*s;t++;}}for(int i=0 ; i<t ; i++) {for(int j=m ; j>=goods[i].v ; j--)f[j] = max(f[j], f[j - goods[i].v] + goods[i].w);}printf("%d",f[m]); }

五、多重背包問題 3 終極版 男人八題之一

數據范圍

0 < N ≤ 1000
0 < V ≤ 20000
0 < vi,wi,si ≤ 20000

現在數量級超級大,用二進制優化方法也頂不住了

單調隊列優化方法 #我現在還不會等我學完了回來補充
大佬題解

這是多重背包問題1的代碼 for(int i=0 ; i<n ;i++){int v,w,s;scanf("%d%d%d",&v,&w,&s);for(int j=m ; j>=0 ; j--){for(int k=1 ; k<=s && k*v <= j ; k++){f[j] = max(f[j], f[j - k * v] + k * w);}}}

六、混合背包問題

有 N 種物品和一個容量是 V 的背包。

物品一共有三類:

第一類物品只能用1次(01背包);
第二類物品可以用無限次(完全背包);
第三類物品最多只能用 si 次(多重背包);
每種體積是 vi,價值是 wi

求解將哪些物品裝入背包,可使物品體積總和不超過背包容量,且價值總和最大。
輸出最大價值。

輸入格式

第一行兩個整數,N,V,用空格隔開,分別表示物品種數和背包容積。

接下來有 N 行,每行三個整數 vi, wi, si,用空格隔開,分別表示第 i 種物品的體積、價值和數量。

si = ?1 表示第 i 種物品只能用 1 次;
si = 0 表示第 i 種物品可以用無限次;
si > 0 表示第 i 種物品可以使用 si 次;

輸出格式

輸出一個整數,表示最大價值。

數據范圍

0 < N, V ≤ 1000
0 < vi, wi ≤ 1000
?1 ≤ si ≤ 1000

輸入樣例

4 5 1 2 -1 2 4 1 3 4 0 4 5 2

輸出樣例:

8

先判斷這個物體屬于哪一類,然后按那一類去轉移

遇到01背包或者完全背包就直接存下來,如果是多重背包就拆成log2個存入

#include<stdio.h> int max(int a,int b){if(a>=b) return a;else return b; } int n,m; int f[1010];struct GOOD{int kind;int v;int w; };struct GOOD goods[10010]; int t=1; int main(){scanf("%d%d",&n,&m);for(int i=0; i<n ;i++){ //錄入物體數組int v,w,s;scanf("%d%d%d",&v,&w,&s);if(s<0) {goods[t].kind=-1;goods[t].v=v;goods[t].w=w;t++;}else if(s==0){goods[t].kind=0;goods[t].v=v;goods[t].w=w; t++;}else{for(int k=1; k<=s ; k*=2){s -= k;goods[t].kind = -1; //拆完以后就變成01背包了 ,所以是-1 goods[t].v = v*k;goods[t].w = w*k;t++;}if(s>0){goods[t].kind = -1; goods[t].v = v*s;goods[t].w = w*s;t++;}}}//遍歷物體數組for(int i=1 ; i<t ; i++){ if(goods[i].kind < 0){ //01背包從大到小 for(int j=m ; j>=goods[i].v ; j--) {f[j] = max(f[j], f[j-goods[i].v] + goods[i].w);}}else{ //完全背包從小到大 for(int j=goods[i].v ; j<=m ; j++){f[j] = max(f[j], f[j-goods[i].v] + goods[i].w);} }}printf("%d",f[m]); }

七、二維費用背包問題

有 N 件物品和一個容量是 V 的背包,背包能承受的最大重量是 M

每件物品只能用一次。體積是 vi重量是 mi,價值是 wi

求解將哪些物品裝入背包,可使物品總體積不超過背包容量,總重量不超過背包可承受的最大重量,且價值總和最大。
輸出最大價值。

輸入格式

第一行三個整數,N , V , M,用空格隔開,分別表示物品件數、背包容積和背包可承受的最大重量。

接下來有 N 行,每行三個整數 vi, mi, wi,用空格隔開,分別表示第 i 件物品的體積、重量和價值。

輸出格式

輸出一個整數,表示最大價值。

數據范圍

0 < N ≤ 1000
0 < V, M ≤ 100
0 < vi, mi ≤100
0 < wi ≤ 1000

輸入樣例

4 5 6 1 2 3 2 4 4 3 4 5 4 5 6

輸出樣例

8
f[i][j] 為體積是i,重量是j時背包的最大價值。

就是把質量看成和體積同等地位的一種限制條件,再來次循環 ,若再多一個限制條件就變成三維數組即可

#include<stdio.h> int max(int a,int b){if(a>=b) return a;else return b; } int f[110][110]; int main(){int n,v,m;scanf("%d %d %d",&n,&v,&m);for(int i=0;i<n;i++){int a,b,c;scanf("%d%d%d",&a,&b,&c);for(int j=v;j>=a;j--)for(int k=m;k>=b;k--) //就是把質量看成和體積同等地位的一種限制條件,再來次循環 f[j][k]=max(f[j][k],f[j-a][k-b]+c);}printf("%d",f[v][m]); }

八、分組背包問題

N 組物品和一個容量是 V 的背包。

每組物品有若干個,同一組內的物品最多只能選一個
每件物品的體積是 vij,價值是 wij,其中 i 是組號,j 是組內編號。

求解將哪些物品裝入背包,可使物品總體積不超過背包容量,且總價值最大。

輸出最大價值。

輸入格式

第一行有兩個整數 N,V,用空格隔開,分別表示物品組數和背包容量。

接下來有 N 組數據:

每組數據第一行有一個整數 Si ,表示第 i 個物品組的物品數量;
每組數據接下來有 Si 行,每行有兩個整數 vij , wij ,用空格隔開,分別表示第 i 個物品組的第 j 個物品的體積和價值;

輸出格式

輸出一個整數,表示最大價值。

數據范圍

0 < N, V ≤ 100
0 < Si ≤ 100
0 < vij, wij ≤ 100

輸入樣例

3 5 2 1 2 2 4 1 3 4 1 4 5

輸出樣例:

8 f[i][j] 為前i組物品,體積是j的情況下,背包的最大價值 //很像01背包問題,只是其中每個物品都可以在此細分并且要選出其中最優的那個 forint i = 0; i<n ; i++{ //循環每一組for(int j=m;j>=v;j--){ //循環體積for() //循環組中每一個物品 , 也可以一個不選f[j] = max(...);} }

多重背包問題是分組背包問題的特殊情況,多重背包問題是每一個物體有s+1種選法(不選,和選1到s個),可以想象把這s+1種選法變成s個物體打包成一個物體組變為分組背包問題,分組背包問題也是s+1種,但沒法優化。

總結

以上是生活随笔為你收集整理的背包问题 c语言版的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。