C語言(CED)01背包——動態規劃第二題

一、問題描述

給定n種物品和一個背包。物品i的質量Wi,其價值Vi,背包的容量為c。問如何選擇裝入背包中的物品,使得裝入背包中的物品總價值最大?

二、解題思想

? ? ? ? 01背包和最長公共子序列都是動態規劃題目中求最優解的問題,不同在于,01背包問題,即使發現物品可以放入背包,但是在采取放或者不放的措施時,還要進行選擇。(這就是保證最優解的條件)

? ? ? ? 我們先根據題意有如下假設:假設物品的種類和背包的容量是變化的,是逐漸增多的。我們每個不同容量的背包的最大價值,建立在先前背包最大價值的基礎上。例如:背包容量為5的最優解,建立在背包容量為4的最優解的基礎上。

? ? ? ? 既然容量和物品種類是變化的,那么我們建立一個二維數組(下文均稱最佳價值表),橫向代表背包容量,縱向代表物品種類,將每個不同容量的背包的最優解記錄在最佳價值表里(這個最佳價值表記錄的是滿足題意的不同背包容量的最優解),如下圖所示。由此正式開始思解題算法:思考遞推式。

? ? ? ?依照假設,就會得出如下情況:

A、當只有0種物品時,無論背包的容量是多少,背包內物品的總價值都為0(因為沒有東西可放);當物品的種類很多時,但是背包的容量為0,背包內物品的總價值仍然為0(因為放不進去啊!)所以這個最佳價值表的第0行,第0列都是“0”,其中V[0][0]=0,不是因為我在程序中按照上述賦值為0,其真實原因是:只要是宏變量,聲明在頭文件下的變量,其初值都會自動為0。上述內容相當于對這個最佳價值表做了一個初始化,如下圖所示:

B、當物品的種類和背包容量按照上圖遞增時,就會又出現一種情況:物品不能放入背包(因為物品的質量大于當前背包可容納的質量)、物品能放入背包。

C、物品能放入背包也要分兩種:物品要放入、物品不放入。那么可能你要提問了,為什么物品能裝入但是卻不選擇裝入呢?

因為我們這個二維數組存儲的是背包的最佳價值表。這個物品雖然能放到背包內,但是如果它的體積過大,放入后勢必會影響后續的物品放入,導致此最佳價值表違反了其“最佳”二字。如果第?個物品沒有裝入背包,則背包中物品價值就等于把前??1個物品裝入容量為?的背包中所取得的價值; 如果把第?個物品裝入背包,則背包物品的價值等于第??1個物品裝入容量為??weight[?]的背包中的價值加上第?個物品的價值value[?]。

綜上:

A、V[i][0]=V[0][j]=0? ? ? ?//簡單初始化

B、V[i][j]=V[i-1][j]? ? ? ? ? //物品不能放入

C、V[i][j]=max(v[i-1][j-weight[i]]+value[i],v[i-1][j])? ?//物品能放入

表達式詳細解析:

看到這,有的讀者就會有很多問題,我來以一問一答的形式讓大家更加來了解這道題目的解題思想:

Q1:為什么表達式中每次用當前背包的總容量和新出現的物品的質量作比較,而不是用背包剩余的容量與新出現的物品的質量作比較?

A1:這個問題也是我接觸動態規劃問題之初提過的一個問題。01背包是典型的動態規劃問題,既然是動態規劃問題,那么就要動起來,整個問題中,動就只有一個——物品放入背包中。你可以設想一下,假設你在實際操作的時候,雖然給出的物品很多,但因為你目光有限,所以看到的東西也是一個一個進入眼簾。你可能會先將一個物品放入背包,但是因為后來出現了又小、價值又高的物品,你在權衡之后,可能又得把之前放入的這個物品掏出,騰出空間來放當前這個質量小、價值高的物品·······說了這么多鋪墊,可能有的人已經明白了:這道題的關注點只在于背包能放得下還是放不下,而不是背包放進一些東西之后剩余的空間放的下還是放不下。這個其實直接可以從上述C的表達式可以看出,即:發現物品可放入的時候,你需要以背包的總價值作為衡量依據,到底是放入價值更高了(此時有的人可能會問了,難道物品放入背包后價值還會降低?因為放入物品的時候,需要騰出一定的空間,這就需要拿出背包里的物品,所以放入物品價值不一定更高)還是不放價值更高了,所以用一個max函數來比較。如果發現放入價值高,那就得騰出空間(用最佳價值表的縱軸坐標)

Q2:做這類問題的時候,有什么秘訣沒有?

A2:1、既然是動態問題,那么我們的大腦就得靈活,而且得聯系實際情況,把大問題化成簡單的小問題。計算機是一個很傻的處理機器,重復做著相同的工作,唯一的優點就是快,我們需要做的事情就是告訴他應該做什么事情,做的次數等,其他的就不需要多想了。?2、第二點就是不要多想,直接推導遞推式,然后求解,就像Q1的那種問題就不要多加考慮了。

三、具體實現

#include<stdio.h>
#include<stdlib.h>
#include<iostream>
using namespace std;
int V[100][100];//用來存儲背包的最大價值
int weight[100]; //存儲物品的重量
int value[100];//存儲物品的價值
int state[100];//存儲物品的選取狀態
int max(int a,int b)//比較價值大小函數
{if (a>=b)return a;else return b;
}
int KnapSack(int n,int weight[],int value[],int state[],int capacity)//動態規劃求解函數
{int i,j;//循環變量//V[0][0] = 0;for (i=1;i<=n;i++)//當j=0時(j代表背包容量),0容量什么都裝不進去,所以V[i][j]=0;V[i][0]=0;for (j=1;j<=capacity;j++)//當i=0時,代表沒有物品,即使背包容量再大,其V[0][j]=0;V[0][j]=0;//#####下面進行判斷######for (i=1;i<=n;i++)//i代表物品,j代表背包容量{//j代表背包的容量,將其從0逐步增加到輸入的背包容量,相當于以背包的容量為限制,一步一步求得最大價值的方法。for (j=1;j<=capacity;j++){if(j<weight[i])//表示該物品?不能裝入背包。V[i][j]=V[i-1][j];//表明此處的價值等于前i-1個物品裝入的價值。else//第?個物品的重量小于背包的容量后就會有兩種情況,一種放入,一種不放入,求這兩種情況中Value最大的。V[i][j]=max(V[i-1][j],V[i-1][j-weight[i]]+value[i]);//如果把第?個物品裝入背包,則背包物品的價值等于第??1個物品裝入容量位??weight[?]的背包中的價值加上第?個物品的價值value[?]//如果第?個物品沒有裝入背包,則背包中物品價值就等于把前??1個物品裝入容量為?的背包中所取得的價值。}}j=capacity;//為標記“哪件物品放入背包”做準備for(i=n;i>=1;i--)//標記選出的物品函數{if(V[i][j]>V[i-1][j]){state[i]=1;//1表示選中j=j-weight[i];}elsestate[i]=0;//0表示未選中}printf("選中的物品是:");for(i=1;i<=n;i++)printf("%d ",state[i]);printf("\n");cout<<"V[i][j]中的數字是:\n";for(int i=0;i<=n;i++){for(int j=0; j<=capacity;j++){printf("%3d", V[i][j]);if (j == capacity){printf("\n");}}}return V[n][capacity];
}
int main()
{int s;//獲得的最大價值int n = 0;//用于循環輸入cout<< "請輸入物品的個數:";cin >> n;cout << "請輸入物品對應的質量:";for (int i = 1; i <= n; i++)cin >> weight[i];cout << "請輸入物品對應的價值:";for (int i = 1; i <=n; i++)cin >> value[i];cout << "請輸入背包最大容量:";int capacity;cin >> capacity;//背包最大容量s = KnapSack(n, weight, value, state, capacity);cout<<"最大物品價值為:"<<s<<endl;system("pause");return 0;
}

其中有一個for循環用來找出哪些東西被放入背包中,1代表放入,0代表沒放入。?

為了方便理解,我來多貼幾張圖,在這里就不做gif圖了,大家順著我的這個圖去理解。

函數種前兩個for循環程序執行之后:(藍色區域為最佳價值表區域)

這個是只有物品1的時候:?

出現物品2:其中綠色的6就是一個在比較之后填入的價值,綠色的9是當前兩個物品的總和。

按照函數中的算法,一個一個模擬的把數字填寫進去,相信你就會理解這道題目了。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/531097.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/531097.shtml
英文地址,請注明出處:http://en.pswp.cn/news/531097.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

C語言(CED)gameboy接餡餅問題

一、題目大意 都說天上不會掉餡餅&#xff0c;但有一天gameboy正走在回家的小徑上&#xff0c;忽然天上掉下大把大把的餡餅。這餡餅別處都不掉&#xff0c;就掉落在他身旁的10米范圍內。餡餅如果掉在了地上當然就不能吃了&#xff0c;所以gameboy馬上卸下身上的背包去接。但由…

C語言(CED)遞歸實現漢諾塔問題

一、問題大意 大梵天創造世界的時候做了三根金剛石柱子&#xff0c;在一根柱子上從下往上按照大小順序摞著64片黃金圓盤。大梵天命令婆羅門把圓盤從下面開始按大小順序重新擺放在另一根柱子上。并且規定&#xff0c;任何時候&#xff0c;在小圓盤上都不能放大圓盤&#xff0c;…

C語言(CED)智力大沖浪——貪心算法第一題

一、題目大意 小偉報名參加中央電視臺的智力大沖浪節目&#xff0c;本次挑戰賽吸引了眾多參賽者&#xff0c;主持人為了表彰大家的勇氣&#xff0c;先獎勵每個參賽者m元。先不要太高興&#xff01;因為這些錢還不一定都是你的&#xff01;接下來主持人宣布了比賽規則&#xff…

C語言(CED)鋼條最優切割收益

目錄 一、題目大意 二、大致思路 三、具體實現 一、題目大意 一家公司購買長鋼條&#xff0c;將其切割成短鋼條出售&#xff0c;切割本身沒有成本&#xff0c;長度為i的短鋼條的價格為Pi。那給定一段長度為n的鋼條和一個價格表Pi,求鋼條的切割方案使得收益Rn最大。提示&…

C語言(CED)如何用sort函數根據結構體里的某一屬性進行排序

&#xff08;請先看置頂博文&#xff09;本博打開方式&#xff0c;請詳讀_liO_Oil的博客-CSDN博客_怎么把androidstudio卸載干凈 前幾天在編寫代碼的時候&#xff0c;突然要根據結構體的屬性進行從小到大的排序&#xff0c;這即是我寫這篇文章的導火索。 正如大家所知…

撰寫paper時,如何在word里輸入圖片或其他文獻(PDF)里的公式?(更新時間2022.03.01)

我們在寫paper時&#xff0c;經常會遇到在Word里編寫數學公式的問題&#xff0c;其中大多數公式是已經存在的&#xff0c;所以只需要識別、復制、粘貼即可&#xff0c;那么接下來&#xff0c;我就介紹一下“Mathtype”“Mathpix”的方法&#xff0c;分為所需軟件、軟件操作、公…

家里接入某運營商300M寬帶,為何網速還是很慢?(還未裝修房屋的請進來)

&#xff08;請先看置頂博文&#xff09;本博打開方式&#xff0c;請詳讀_liO_Oil的博客-CSDN博客_怎么把androidstudio卸載干凈 引言&#xff1a;家里接入300M的寬帶&#xff0c;但是自我感覺網速不佳&#xff0c;遂結合所學知識&#xff0c;對此問題進行分析、研究和調察&…

(CED)列指針與行指針的聯系與區別

一、列指針&#xff08;豎為列&#xff09; 1、列指針相關定義 列指針&#xff1a;被稱為是指針變量指向二維數組的某個元素 一般使用時會有如下定義&#xff1a; int a[3][4]{1,2,3,4,5,6,7,8,9,10,11,12}; int *p;而上述代碼定義的指針p&#xff0c;一般按照下表方式指向…

C語言(CED)C語言中雙引號和單引號的區別

最簡單的區別&#xff1a; 在字符型變量賦初值時&#xff0c;用單引號&#xff1b;為字符串變量賦初值時用雙引號&#xff01; 具體區別&#xff1a; 1、大小 單引號引起的一個字符&#xff0c;其大小為1個Byte。 雙引號引起的字符串&#xff0c;因為在其結尾需加一個二進…

一、Pytho第一課——Python安裝及配置路徑方法(最詳細小白教程,沒有之一。如若不懂,不是還可以私信嘛!對吧?)

目錄 一、下載軟件 二、安裝 三、編輯器 四、在Pycharm上成功運行Python程序&#xff08;配置Python解釋器&#xff09; 一、下載軟件 官方下載地址&#xff1a;https://www.python.org/downloads/&#xff08;打開似乎很吃力&#xff0c;必要時刻“掛燈”&#xff09; …

二、Python第二課——變量命名規則及字符串變量相關函數

目錄 一、變量命名規則 二、字符串變量及相關函數 1、字符串變量 2、相關函數 最后瑣碎雜物&#xff1a; 1、字符串之間的拼接 2、字符串格式控制&#xff08;制表符和換行&#xff09; 一、變量命名規則 正如其他編程語言一樣&#xff0c;程序離不開聲明變量&#x…

三、Python第三課——Python中數字的用法及編碼原則(Python禪意)

目錄 一、Python中的數字 1、整數 2、浮點數 3、整數、浮點數和字符串的聯系和區別 二、編碼原則 1、為代碼增加注釋 2、Python 禪意 A、編碼精美 B、避繁就簡 C、無簡就繁 D、使用常規方法解決問題 E、先有效、再精巧、逐步升華 一、Python中的數字 編程中&#…

四、Python第四課——Python中列表及其操作(增刪改查)

目錄 一、Python中的列表 1、列表的定義和賦值 2、列表的使用 二、列表的“增刪改查” 1、列表中元素的增加 A、在列表尾添加元素 B、在列表中插入元素 2、列表中“元素的刪除” A、使用del語句刪除元素 B、使用pop()函數刪除元素 C、彈出列表中任何位置元素…

五、Python第五課——Python中組織列表的相關函數

目錄 一、用sort()函數對列表進行永久排序 二、用sorted()函數對列表進行臨時排序 三、用reverse()函數對列表進行列表原始排序的逆序輸出 四、使用len()函數確定列表長度 創建列表后&#xff0c;內部的元素逐漸增多&#xff0c;其排列順序也是無法預測的&#xff0c;因為…

如何正確下載、安裝Codeblocks?

目錄 一、Codeblocks的下載 二、Codeblocks的安裝 三、Codeblocks的運行 相信很多同學在初學C語言時都會選擇一個短小精悍的代碼編輯器&#xff0c;如CodeBlocks&#xff08;不說別的了&#xff0c;直接切入正題&#xff09;。 在2020年&#xff08;今年&#xff09;3月份-…

Python:創建列表,其中包含數字1-1000000,為什么Pycharm控制臺結果顯示不完整?

目錄 一、問題描述&#xff08;尋找解決方法的同學直接看“標題二”&#xff09; 二、解決辦法 一、問題描述&#xff08;尋找解決方法的同學直接看“標題二”&#xff09; 在學習Python過程中遇到一個這樣的問題&#xff0c;也算是一個小BUG吧。題目大意是這樣的&#xff…

六、Python第六課——Python中的for循環及數字列表

目錄 一、Python中的for循環 1、for循環語句的聲明。 2、for循環縮進常見問題 二、數字列表 1、函數range() 2、使用range()函數創建數字列表 3、使用一系列函數處理數字列表&#xff08;統計&#xff09; 4、列表解析&#xff08;生成列表的簡潔方法&#xff09; 一…

七、Python第七課——有關列表的二三事(切片、切片的遍歷和復制)

目錄 一、切片 二、遍歷切片 三、列表的復制 一、切片 此前&#xff0c;我們學習了如何訪問單個列表以及如何處理列表中的所有元素&#xff0c;那么我們如何處理列表中的部分元素呢&#xff1f;這就引出一個概念“切片” 。我們可以把列表看成是面包&#xff0c;“切片”…

八、Python第八課——元組與列表、代碼格式

&#xff08;請先看置頂博文&#xff09;https://blog.csdn.net/GenuineMonster/article/details/104495419 目錄 一、元組的定義 二、元組的遍歷 三、代碼格式 一、元組的定義 1、元組&#xff1a;不可變的列表稱為元組。這個是相對于普通列表而言的&#xff0c;普通列表…

九、Python第九課——Python中的if語句與運用

&#xff08;請先看置頂博文&#xff09;https://blog.csdn.net/GenuineMonster/article/details/104495419 目錄 一、if語句 1、檢查變量存儲的值是否相等 2、判定字母或字符串時區別大小寫 3、檢查多個條件 4、檢查特定值是否在列表中 二、if-else語句和if-elif-el…