【算法速成課2 | 題單】背包問題

專欄指路:《算法速成課》


前導:

動態規劃問題中最入門、也最多變的,當屬背包問題

簡單來說,就是在有限的空間,(花費最小的代價)達成最大的收益

本文會講一些常見的背包問題(可通過目錄挑選題目),難度普及提高左右,配套一些例題。

個人認為比 oiwiki 更適合初學者一點,不過肯定沒人家全。

(1)0/1 背包

有 n?個物品,每物品的重量為 a_i

我們有一個最大承重為 v?的背包。

從 n?個物品中選若干個裝入背包,使得所選物品的和 s?盡量接近 v?(s\leq v) ,即 v - s?的值最小。

標題的 0 和 1 指的是每個物品有不選和選兩種狀態。

根據這個定義狀態 f[i] 為 1 就表示背包里放 i 重量是可能的,0 則不可能。

代碼:

#include<bits/stdc++.h>
using namespace std;int a[30];
bool f[20010];   //f[i]:1 表示背包里放 i重量是可能的,0 則不可能 
//要多開一點空間,以防爆炸 int main() {ios::sync_with_stdio(false);   //關同步流,可以讓 cin更快一點 cin.tie(0);   //打了這兩行就不可以用 scanf和 printf了 int V, n;cin >> V >> n;for (int i = 1; i <= n; i++) {cin >> a[i];    //讀入 }memset(f, 0, sizeof(f));   //初始化 f[0] = 1;           //一開始背包里啥也沒有,0 是可能的 for (int i = 1; i <= n; i++) {for (int j = V; j >= a[i]; j--) {   //因為每個東西只有一個,所以要反著放//正著放就可以一種東西疊加,適合一個東西有無限個的情況 if (f[j - a[i]] == 1) {f[j] = 1;   //如果 j - a[i]是可能的,那么再放一個 a[i]也是可能的 }}}int p;for (int i = V; i >= 0; i--) {  //找最大的那個可能的 if (f[i] == 1) {p = i;break;}}cout << V - p << "\n";   //輸出差值 return 0;
}

例題:

洛谷 P2925 [USACO08DEC] Hay For Sale S

例題可以和上面代碼一樣做,但還可以有一種寫法:

#include <bits/stdc++.h>
using namespace std;int f[50010], a[5010];
//f[i]:表示給你 i空間,你最多可以放多少
//f[i] <= i int main() {ios::sync_with_stdio(false);cin.tie(0);int V, n; cin >> V >> n;for (int i = 1; i <= n; i++) {cin >> a[i];    //讀入 }memset(f, 0, sizeof(f));for (int i = 1; i <= n; i++) {for (int j = V; j >= a[i]; j--) {f[j] = max(f[j], f[j - a[i]] + a[i]);}}cout << f[V];//輸出給你 V空間,最多可以放多少return 0;
}

練習:

有 T?個數列。 設 S_i?為從第 i?個數列選若干個數的和。

(當然,一個數列有很多個 S_i

設整數 K?滿足所有數列 S_i 中都有 K,求 K?的最大值。

解析:

每個數列都搞一個 0/1 背包,如果這個數列可以達到 i 那么 sum[i]++。

最后找最大的 i 滿足 sum[i] = T。

代碼就不給了。

例題 2:

小明背著一個背包(最大能帶的重量為 T)走進一個山洞。

山洞里有 n?個寶石,第 i?個 寶石的重量為 t_i,拿到寶石店能賣 m_i?塊錢。

求最多能賣多少錢。

基本和之前的代碼一樣,只不過定義狀態 f[i] 為給你 i 空間,你最多可以賣多少錢

核心代碼:

for (int i = 1; i <= n; i++) {for (int j = T; j >= t[i]; j--) {f[j] = max(f[j], f[j - t[i]] + m[i]);}
}cout << f[T] << "\n";

例題 3(有點難):

洛谷P3010 [USACO11JAN] Dividing the Gold S

其實很簡單,想不通的話看代碼一下就懂了。

就是模數模完可能是零有點惡心:

#include<bits/stdc++.h>
using namespace std;const int N = 310, M = 6e5 + 10;   //最多就是 n * a[i]
const int P = 1000000;int a[N], f[M];  //f[i]: 有多少種加數方案能得到 i
bool g[M]; //g[i]: 0不可能,1可能
//因為對 1,000,000 取余完可能為 0,所以要多開一個 g 數組判斷當前 i 是否能得到int main() {ios::sync_with_stdio(false);cin.tie(0);int n;cin >> n;int sum = 0;for (int i = 1; i <= n; i++) {cin >> a[i];sum += a[i];}memset(f, 0, sizeof(f));memset(g, 0, sizeof(g));f[0] = 1;g[0] = 1;for (int i = 1; i <= n; i++) {for (int j = sum; j >= a[i]; j--) {f[j] = ( f[j] + f[j - a[i]] ) % P;g[j] |= g[j - a[i]] ;//位運算,如果 g[j - a[i]]等于 1 那么g[j] 也等于 1//反之 g[j] 不變}}for (int i = sum / 2; i >= 0; i--) {if (g[i] != 0) {  // i 可以達到cout << (sum - i) - i << "\n";   // sum - i 是另一組數長度 cout << f[i] << "\n";break;}}return 0;
}

(2)完全背包

有 n 種物品,每物品的重量為 a_i有無限個

我們有一個最大承重為 v?的背包。

從 n 種物品中選若干個裝入背包,使得所選物品的和 s?盡量接近 v?(s\leq v) ,即 v - s?的值最小。

輸入第 i?種寶石的重量為 t_i,拿到寶石店能賣 m_i?塊錢。

和上面 0/1 背包的例題 2 一模一樣,除了物品有無窮多個。

那么第二個循環就變成正序。

代碼:

#include<bits/stdc++.h>
using namespace std;
const int N = 1010;int t[N], m[N];
int f[N];int main() {ios::sync_with_stdio(false);cin.tie(0);int T, n;cin >> T >> n;for (int i=1; i<=n; i++) {cin >> t[i] >> m[i];}memset(f, 0, sizeof(f)); for (int i = 1; i <= n; i++) {for (int j = t[i]; j <= T; j++) {    //就是這里!!改成正序的,就代表單種物品可以自己和自己疊加f[j] = max(f[j], f[j - t[i]] + m[i]);}}cout << f[T] << "\n";return 0;
}

稍有難度的例題:

洛谷 P3027 [USACO10OCT] Making Money G

洛谷那邊的題面就像一坨烤糊的司康,,在那邊提交就行了題意還是看我寫的:

小明帶著 m?塊錢走進一個山洞挖寶石,然后帶著寶石到市場去賣。

山洞里有 n?種寶石(每種寶石無限多個),第 i?種寶石的價格為 c_i,拿到寶石店能賣 r_i?塊錢。

假如小明能在市場賣掉所有采購的寶石,

求小明所獲得的最大利潤(未花完的錢算入利潤里面)的最大值。

解析:

換湯不換藥,一開始就把 r 數組轉換成利潤,之后正常完全背包。

最后從 f[m] 找到第一個 f 值不等于 f[m] 的值的前一位 p,就是真正買寶石花的錢。

輸出答案時?f[m] + m - p,因為 m - p 是未花完的錢。

#include<bits/stdc++.h>
using namespace std;const int N = 110, M = 1e5 + 10;int c[N], r[N];
int f[M];   // f 要開大點int main() {ios::sync_with_stdio(false);cin.tie(0);int n, m;cin >> n >> m;for (int i = 1; i <= n; i++) {cin >> c[i] >> r[i];r[i] -= c[i];   //先把 r 數組轉化成利潤}memset(f, 0, sizeof(f)); for (int i = 1; i <= n; i++) if(r[i] > 0) {   //有利潤才干事for (int j = c[i]; j <= m; j++) {f[j] = max(f[j], f[j - c[i]] + r[i]);}}int p = m;while ( p > 0 && f[p] == f[p - 1]) {    //尋找真正發生“質變”的那個數,那才是真正花的錢p --;}cout << f[p] + m - p << "\n";return 0;
}

有點小巧思的例題:

P2563 [AHOI2001] 質數和分解 - 洛谷

數據范圍很小,很多種方法都可以過。

這里我就用線性篩篩出質數,然后在質數數組上完全背包。

代碼:

#include<bits/stdc++.h>
using namespace std;const int N = 310;
bool v[N];
int pr, prime[N], f[N];void init() {memset(v, 0, sizeof(v));v[1] = 1;pr = 0;for (int i = 2; i <= N - 10; i++) {if (!v[i]) {pr ++;prime[pr] = i;}for (int j = 1; j <= pr && i * prime[j] <= N - 10; j++) {int pj = prime[j];v[i * pj] = 1;if (i % pj == 0) {break;}}}
}int main() {init();int n;while (scanf("%d", &n) != EOF) {memset(f, 0, sizeof(f));f[0] = 1;for (int i = 1; i <= pr; i ++) {for (int j = prime[i]; j <= n; j ++) {f[j] += f[j - prime[i]];}}cout << f[n] << "\n";}return 0;
}

(3)多重背包

和 0/1 背包一樣,只不過這次每種物品有固定的個數。

例題 & 二進制優化:

281. 硬幣 - AcWing題庫

解析:

為了方便學校 oj 使用,我單開了一篇。

麻煩大家點這個鏈接。

例題 & 單調隊列優化:

(自行百度/oiwiki 單調隊列是什么)

P1776 寶物篩選 - 洛谷

解析:

為了方便學校 oj 使用,我又單開了一篇。

麻煩大家點這個。

背包問題的基礎就到這里啦,還有些變種問題,以后可能會講。

感謝您的閱讀。

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

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

相關文章

計算機視覺與深度學習 | 深度學習圖像匹配算法在不同紋理復雜度場景下的魯棒性和計算效率評估方法

如何評估深度學習圖像匹配算法在不同紋理復雜度場景下的魯棒性和計算效率? 文章目錄 如何評估深度學習圖像匹配算法在不同紋理復雜度場景下的魯棒性和計算效率? 一、評估框架概述 1.1 核心評估維度 1.2 評估流程 二、紋理復雜度場景分類方法 2.1 紋理特征量化指標 2.2 場景分…

AI 提示詞工程與上下文工程:從入門到深入的系統實踐指南

前言近年來&#xff0c;隨著大語言模型&#xff08;LLM&#xff0c;Large Language Model&#xff09;的快速發展&#xff0c;提示詞工程&#xff08;Prompt Engineering&#xff09;與上下文工程&#xff08;Context Engineering&#xff09;逐漸成為 AI 應用開發中至關重要的…

救火!Linux服務器慢如蝸牛:一套從根源到應用的性能問題診斷全攻略

前言&#xff1a;從“玄學”到“科學” “服務又卡了&#xff01;” 這是我們每個Linux運維/SRE工程師最不想聽到&#xff0c;卻又最常聽到的一句話。隨之而來的&#xff0c;往往是開發、產品、甚至老板的連環追問。此時&#xff0c;一個經驗不足的工程師可能會立刻登錄服務器&…

BYOFF (Bring Your Own Formatting Function)解析(80)

BYOFF (Bring Your Own Formatting Function)解析(80) 看起來不錯!要注意的是,我們并沒有真正使用任何自定義的特殊標記。其中 “Question”(問題)、“Answer”(答案)、井號(#)以及 EOS 標記,都是分詞器詞匯表中常見的條目。在本節后續內容中,我們將探討自定義特…

秋招|MCU+RTOS技術棧——面試八股文整理3:STM32

目錄 1.單片機啟動流程 2.看門狗 3.最小系統 4.ROM、RAM、Flash 5.EPROM、EEPROM 6.Bootloader與OTA 1.單片機啟動流程 單片機的啟動流程是指從上電或復位開始到應用用戶主程序執行的一系列自動操作過程&#xff0c;不同架構的單片機流程略有差異&#xff0c;但核心邏輯…

在 CentOS 9 上安裝 Docker 的完整指南

1.準備安裝環境&#xff08;1&#xff09;禁用防火墻與SELinux[rootlocalhost ~]# systemctl disable --now firewalld.service Removed "/etc/systemd/system/multi-user.target.wants/firewalld.service". Removed "/etc/systemd/system/dbus-org.fedoraproj…

如何實現外語播客的中文同傳?

Bayt播客可以將任何語言的外語播客&#xff08;英文播客、日文播客、韓文播客等&#xff09;轉換成中文音頻收聽&#xff0c;實現同聲傳譯。并且還提供中文和原文的雙語字幕。幫助你跨越語言障礙&#xff0c;收聽高質量外語內容 核心功能&#xff1a; 1、所有語言的播客均可轉…

Spring Cloud ------ Gateway

一、什么是網關 經常面試的人肯定知道&#xff0c;在去公司面試時&#xff0c;通常不會直接去面試官那里面試&#xff0c;而是先去前臺進行詢問面試官的所在地&#xff0c;并進行一些相關登記。而網關對于一個微服務項目來說&#xff0c;就類似于一個前臺&#xff0c;打到微服…

Go初級之九:Select 與并發控制

在Go語言中&#xff0c;select語句是處理并發編程的核心工具之一。它讓我們能夠優雅地管理多個通道操作&#xff0c;實現高效的并發控制。 1. Select 語句基礎 1.1 Select 的基本語法 package mainimport ("fmt""time" )func main() {ch1 : make(chan stri…

使用 Acme.sh 獲取和管理免費 SSL 證書

Acme.sh 是一個開源的 Shell 腳本工具&#xff0c;支持從 Let’s Encrypt 等證書頒發機構獲取免費的 SSL/TLS 證書。它支持多種驗證方式&#xff0c;并能自動續期證書&#xff0c;適合個人網站或企業使用。 目標 同時支持&#xff0c;主域名和泛域名 安裝 Acme.sh獲取源碼 git …

docker-compose跨節點部署Elasticsearch 9.X集群

系列文章目錄 提示:這里可以添加系列文章的所有文章的目錄,目錄需要自己手動添加 例如:第一章 Python 機器學習入門之pandas的使用 提示:寫完文章后,目錄可以自動生成,如何生成可參考右邊的幫助文檔 文章目錄 系列文章目錄 前言 一、環境準備 二、遇到的問題與分析 三、配…

【面試場景題】spring應用啟動時出現內存溢出怎么排查

文章目錄一、定位 OOM 類型二、基礎排查&#xff1a;調整 JVM 參數與日志三、堆內存溢出&#xff08;Heap Space&#xff09;排查1. 分析堆轉儲文件2. 典型場景與解決四、元空間溢出&#xff08;Metaspace&#xff09;排查1. 分析類加載情況2. 典型場景與解決五、直接內存溢出&…

2025年經濟學專業女生必考證書指南:打造差異化競爭力

在數字經濟快速發展的2025年&#xff0c;經濟學專業女生面臨著諸多機遇與挑戰。單純的理論知識已經難以滿足職場需求&#xff0c;企業更看重解決實際問題的能力&#xff0c;特別是將數據轉化為商業洞察的專業技能。各類專業資質認證可以成為系統提升能力的途徑之一&#xff0c;…

【CAN通信】AUTOSAR架構下TC3xx芯片是如何將一幀CAN報文接收上來的

目錄 前言 正文 1.背景介紹 2.CAN報文硬件原理 3.CAN接收軟件實現 3.1. vCan_30_Mcan_Interrupt 3.2. vCan_30_Mcan_RxInterrupt 3.3. vCan_30_Mcan_RxBasicCanHandling 4.總結 前言 在《【CAN通信】AUTOSAR架構下TC3xx芯片是如何將一幀CAN報文發送出去的》一文中我們…

STM32H750 RTC介紹及應用

第十一章 RTC介紹及應用 1. RTC 簡介 RTC&#xff08;Real-Time Clock&#xff0c;實時時鐘&#xff09;是 STM32H750VBT6 中用于提供日歷和時鐘功能的低功耗外設&#xff0c;即使主電源關閉&#xff0c;只要 VBAT&#xff08;備份電源&#xff09;供電&#xff0c;RTC 仍能持續…

飛網自適應通信:IPv4 與 IPv6 環境下的高效互聯

一、網絡連接的難題與飛網的解決方案 在日常生活中&#xff0c;我們常常會碰到這樣的場景&#xff1a;在家用手機訪問公司電腦里的重要文件&#xff0c;或者遠程連接家里的NAS設備查看照片和視頻。這些操作都需要設備之間建立起安全又穩定的連接。然而&#xff0c;現實中的網絡…

拉格朗日多項式

最近打的幾個比賽沒意思&#xff0c;不是不會就是不會。不過比賽完后看到別人的WP&#xff0c;感覺受益匪淺。先看一個多項式&#xff1a;當輸入Xi時會得到一個Si,要求輸入一定數量的xi 來求[c] 當可以輸入的x個數與c的個數相同時&#xff0c;可以用矩陣直接求解。&#xff08;…

Vue3 + TypeScript 實現文件拖拽上傳

應用效果&#xff1a;實例代碼&#xff1a;CommonApplyBasicInfoForm.vue<script setup lang"ts" name"CommonApplyBasicInfoForm"> ...... // 選擇文件列表 const selectedFiles ref<FileList | null>(null); // 通過 FormData 對象實現文件…

2025全國大學生數學建模C題保姆級思路模型(持續更新):NIPT 的時點選擇與胎兒的異常判定

2025全國大學生數學建模C題保姆級思路模型&#xff08;持續更新&#xff09;&#xff1a;NIPT 的時點選擇與胎兒的異常判定&#xff0c;完整持續更新內容見文末名片 胎兒遺傳信息檢測與臨床決策數學建模分析講義 問題一&#xff1a;Y染色體濃度的影響因素探索——線性回歸的“偵…

【筆記】Software Engineering at Google

聚焦核心原則&#xff0c;挑取最讓我眼前一亮的實踐點&#xff0c;特別是那些能直接啟發或解決我當前工作中痛點的部分。0. 序言 最近集中精力速讀了關于 ?Google 軟件工程實踐? 的諸多資料&#xff08;包括官方出版物、工程博客、技術演講以及社區討論&#xff09;。面對 G…