《算法筆記》總結No.6——貪心

一.簡單貪心

????????貪心法是求解一類最優化問題的方法,它總是考慮在當前狀態下局部最優(或較優)之后,來使全局的結果達到最優(或較優)的策略。顯然,如果采取較優而非最優的策略(最優策略可能不存在或是不易想到),得到的全局結果也無法是最優的。而要獲得最優結果,則要求中間的每步策略都是最優的,因此嚴謹使用貪心法來求解最優化問題需要對采取的策略進行證明。證明的一般思路是使用反證法及數學歸納法,即假設策略不能導致最優解,然后通過一系列推導來得到矛盾,以此證明策略是最優的,最后用數學歸納法保證全局最優。不過對平常使用來說,也許沒有時間或不太容易對想到的策略進行嚴謹的證明(貪心的證明往往比貪本身更難),因此一般來說,如果在想到某個似乎可行的策略之后,并且自己無法舉出反例,那么就勇敢地實現它。

1.組個最小數

給定數字0~9各若干個,可以任意順序排列這些數字,但必須全部使用,且使目標數字盡可能小(當然0不能做首位)比如輸入兩個0、兩個1、三個5和一個8,得到的最小數字就是100155858。


相信大家一下子就可以看出來策略:先從1~9中選擇不為0的最小數輸出,然后從0~9輸出數字,每個數字輸出次數為其剩余個數。

策略正確的證明

  • 首先由于所有數字都必須參與組合,因此最后結果的位數是確定的。?
  • 由于最高位不為0,則選一個盡可能小的數作為首位——最高位定理
  • 其余位數也應該從小到大輸出~

教材上的實在是太抽象了,好像有點錯誤,這里博主自己寫了一種:

#include <cstdio>
#include <vector>
#include <iostream> 
#include <algorithm>
using namespace std;int main() {	vector<int> V;for(int i=1;i<=10;i++){int temp=0;cin>>temp;V.push_back(temp);}sort(V.begin(),V.end());  //直接排成升序 int flag=0;  //標記 for(int i=0;i<=9;i++)if(V[i]!=0){int temp=V[i];V[i]=V[0];V[0]=temp;flag=i;//保存第一個不為0的位置 break;	}for(int i=flag+1;i<=9;i++)  //找更小的頭,直接從flag下一位開始即可,節省時間~ if(V[i]<V[0]&&V[i]!=0){int temp=V[i];V[i]=V[0];V[0]=temp;}for(int i=0;i<=9;i++)cout<<V[i];
}

邏輯上沒什么難度,主要是要想清楚~

2.月餅庫存

  • 輸入:第一行輸入N和M:N位月餅的種類數目,M位市場對月餅的需求總量;接下來的兩行均要輸入N個數:第一行的N個數分別對應當前種類的月餅全部賣出后可以掙多少,而第二行的N個數對應當前月餅的總數量~
  • 要求輸出:在規定需求量下最高收入

????????試想一下你如果作為老板,會怎么去“貪得無厭”?很明顯——只需要在有限的需求量中,盡可能多的賣出單價最貴的月餅,豈不是可以收貨最多的營業額?如下博主自己寫的一種實現,和教材上的也不太一樣:

#include <cstdio>
#include <vector>
#include <iostream> 
#include <algorithm>
using namespace std;struct mooncake{double num;  //總數 double income;  //總收入 double price;   //單價,需要自己計算 
}; int main() {int N,M;cin>>N>>M;vector<mooncake> V;for(int i=1;i<=N;i++) {mooncake temp;V.push_back(temp);}cout<<"請輸入數量:"<<endl;for(int i=1;i<=N;i++) {double num=0;cin>>num;V[i-1].num=num;}cout<<"請輸入總價:"<<endl;for(int i=1;i<=N;i++) {double income=0;cin>>income;V[i-1].income=income;}for(int i=0;i<=N-1;i++) V[i].price=V[i].income/V[i].num; //計算單價//按單價降序排列!保證貴的盡可能多賣for(int i=0;i<=V.size()-1;i++){for(int j=i;j<=V.size()-1;j++)    if(V[j].price>V[i].price)    {mooncake temp;temp=V[j];V[j]=V[i];V[i]=temp;}}for(int i=0;i<=V.size()-1;i++)cout<<"單價第"<<(i+1)<<"高的值為:"<<V[i].income<<" "<<V[i].price<<" "<<V[i].num<<endl;for(int i=0;i<=N-1;i++)cout<<V[i].num<<endl; int j=0;  //使用的下標 double count=0;  //總利潤 while(M>0)  //當還有需求量時 {double doubt=0;doubt=M-V[j].num; //用M減去當前類型的額總量 if(doubt>=0)//減了以后M還有剩余{M-=V[j].num;//當前種類全部賣出 count+=V[j].income;//直接總價相加 j++;cout<<V[j].num;}else if(doubt<0) //不夠減這么多{count+=V[j].price*M;//剩余部分按照單價計算 break; } }cout<<"最高利潤值為:"<<count<<endl;return 0;
}

????????仔細品味上述中的whlie循環:當M還不為0時——即還有需求量,就賣最貴的月餅。按順序一個一個賣:如果當前需求量足以賣完當前種類的全部數量,則直接累加總價;如果不足以賣完當前的全部,則有多少賣多少,按照單價計算即可~?

我們拿教材的測試用例測試一下:

  • 3 20
  • 18 15 10
  • 75 72 45

結果為94.50,和標準答案一致~?

此外這里博主直接把排序寫在main函數了,寫在獨立的函數再調用,對于結構體型的vector好像有點bug,排序不太成功,大家如果知道原因的話可以在評論區寫出來~

二.區間貪心

題干如下:

對于這類題目,只需要牢記——優先選擇左端點大的區間

?

下面來說說為什么要這樣做,如上圖:不難發現,為了保證盡可能多選,當某個較長的區間包含了較短的區間,我們肯定要先選擇最短的區間,這一點很好理解。

????????而對于上面這種情況,比如1和2這種重疊的區間,不難發現,如果選了左端點最大的1區間,只會占到9號位,而選了2號區間則會占到8號位——這顯然不符合貪心盡可能少花錢(少花區間)的思想,因此要選得盡可能靠左,這樣右邊空的會更多~如上,我們手算可以看出來最多有4個不相交的。?

教材上的代碼:?

#include <cstdio>
#include <algorithm>
using namespace std;const int maxn=110;
struct Inteval{int x,y;  //開區間左右端點 
}I[maxn]; bool cmp(Inteval a,Inteval b)
{if(a.x!=b.x)return a.x>b.x;   //左端點從大到小排序 elsereturn a.y<b.y;   //左端點相同的按右端點從小到大排序 
}int main() {int n;while(scanf("%d",&n,n!=0)){for(int i=0;i<n;i++)scanf("%d%d",&I[i].x,&I[i].y);sort(I,I+n,cmp); //排序區間 int ans=1,lastX=I[0].x;//ans記錄總數,lastX記錄上一個被選擇的區間的左端點 for(int i=1;i<n;i++){if(I[i].y<=lastX)   //如果該區間右端點在lastX左邊 {lastX=I[i].x;  //以I[i]作為新選中的區間 ans++;   //不相交的區間個數+1 }	}printf("%d\n",ans);	} return 0;
}

不過博主還是不太喜歡原始數組,下面給一種vector結構體版本:

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;struct section{int x=0;int y=0;//x和y分別為左右端點 
}; int main() {int n=0;vector<section> V;cin>>n;for(int i=1;i<=n;i++) //讀入數據 {section temp;int x=0,y=0;cin>>x>>y;if(x>y)   //防止左端點大于右端點 {int temp1=x;x=y;y=temp1;	}else if(x==y) //若左右端點相同 {i-=1;  //則當前輸入 不算cout<<"不可以輸入相同的左右端點!"<<endl; continue;  //舍棄數據,本次循環作廢~ }	temp.x=x;temp.y=y;V.push_back(temp);}//按要求排序區間優先級 for(int i=0;i<=V.size()-1;i++){for(int j=i+1;j<=V.size()-1;j++){if(V[j].x>V[i].x)  //左端點越大越靠前{section temp=V[j];V[j]=V[i];V[i]=temp;}else if(V[j].x==V[i].x&&V[j].y<V[i].y) //左端點相同的話,右端點小的優先 {section temp=V[j];V[j]=V[i];V[i]=temp;} }}cout<<"順序如下:"<<endl; for(int i=0;i<=V.size()-1;i++)cout<<V[i].x<<"~"<<V[i].y<<endl; int count=1,lastX=V[0].x;//count用來統計總數,lastX是上一個符合條件的區間的左端點for(int i=1;i<=V.size()-1;i++)//直接從第二個區間開始 {if(V[i].y<lastX)  //如果當前區間的右端點不和上一個左端點相加,滿足題意 {lastX=V[i].x;count++;}		} cout<<count<<endl;return 0;
}

測試如下:

?


????????總的來說,貪心法是用來解決一類最優化問題,并希望由局部最優策略來推得全局最優結果的算法思想。貪心算法適用的問題一定滿足最優子結構的性質,即一個問題的最優解可以由他的子問題的最優解有效地構造出來。顯然不是所有問題都適合貪心法,但是這并不妨礙貪心算法成為一個簡潔、實用、高效的算法~

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

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

相關文章

socketserver和WSGI服務端實現教程

Python socketserver 和 WSGI 服務端實現教程 在本文中&#xff0c;我們將詳細解析一個使用 socketserver 模塊實現的簡單 WSGI 服務器。該服務器能夠處理 HTTP 請求&#xff0c;支持 WSGI 應用&#xff0c;并正確處理響應頭和錯誤。 代碼概述 這段代碼定義了一個 run_wsgi …

【深入理解JVM】關于Object o = new Object()

1. 解釋一下對象的創建過程 “半初始化”狀態通常指的是對象在內存分配后、但在完全初始化之前的一種狀態。在Java中&#xff0c;雖然JVM的規范和設計努力避免對象處于這種不穩定的狀態&#xff0c;但在多線程環境下&#xff0c;由于指令重排序等并發問題&#xff0c;仍有可能…

Apache Spark詳解

目錄 性能優化 銀行業務案例&#xff1a; 步驟1&#xff1a;環境準備和數據加載 步驟2&#xff1a;數據探索和預處理 步驟3&#xff1a;特征工程 步驟4&#xff1a;數據轉換 步驟5&#xff1a;構建機器學習模型 步驟6&#xff1a;模型評估 步驟7&#xff1a;部署和監控…

Spring JdbcTemplate使用

maven引入Spring JDBC <dependency><groupId>org.springframework</groupId><artifactId>spring-jdbc</artifactId><version>5.3.19</version></dependency> Spring配置中配置 <!-- DataSource配置 --><bean id"…

java代理簡單理解

一、什么是代理 舉例說明&#xff1a;當我想買一臺電腦&#xff0c;國內太貴了。委托好友A在國外幫忙買。 這個情節中我要實現的動作和好友實現的動作一樣&#xff0c;都是買電腦。好友幫我完成了這個動作&#xff0c;這就是代理。 類A和類B都實現一個interface接口C&#x…

【LeetCode刷題筆記】LeetCode.24.兩兩交換鏈表中的節點

創作不易&#xff0c;本篇文章如果幫助到了你&#xff0c;還請點贊 關注支持一下?>&#x16966;<)!! 主頁專欄有更多知識&#xff0c;如有疑問歡迎大家指正討論&#xff0c;共同進步&#xff01; 更多算法知識專欄&#xff1a;算法分析&#x1f525; 給大家跳段街舞感謝…

新手小白的pytorch學習第一彈-------張量

1 導入pytorch包 import torch2 創建張量&#xff08;tensor&#xff09; scalar標量 scalar torch.tensor(7) scalartensor(7)scalar.ndim查看scalar的維度&#xff0c;因為scalar是標量&#xff0c;所以維度為0 0scalar.shapetorch.Size([])torch.item()7vector&#xf…

Apache功能配置:訪問控制、日志分割; 部署AWStats日志分析工具

目錄 保持連接 訪問控制 只允許指定ip訪問 拒絕指定主機其他正常訪問 用戶授權 日志格式 日志分割 操作步驟 使用第三方工具cronolog分割日志 AWStats日志分析 操作步驟 訪問AwStats分析系統 保持連接 Apache通過設置配置文件httpd-default.conf中相關的連接保持參…

基于Java的科大訊飛大模型API調用實現

寫在前面&#xff1a;因為現在自己實習的公司新拓展的一個業務是結合AI的低代碼平臺&#xff0c;我負責后端的開發&#xff0c;之前一直都是直接使用gpt或者文心一言等ui界面來直接使用大模型&#xff0c;從來沒有自己調接口過&#xff0c;所以本文記錄一下自己第一次使用大模型…

源代碼防泄漏的正確方法

為了保護公司的源代碼不被泄露&#xff0c;IT企業可以采取一系列嚴格的安全措施。這些措施涵蓋技術手段、管理策略和操作流程&#xff0c;形成多層次的防護體系做到源代碼防泄漏工作。 技術手段 1、源代碼加密&#xff1a; 采用高級加密標準&#xff08;AES&#xff09;或其他…

【QT】QComboBox允許輸入查詢,且不區分大小寫

目錄 0.簡介 1.環境 2.詳細代碼 3.參考 0.簡介 項目需求&#xff0c;原本有一個下拉框&#xff0c;但是條目太多&#xff0c;不好搜索&#xff0c;所以用戶要求可以輸入查找 修改前 &#xff1a; 修改后&#xff1a; 1.環境 windows11 vs-code qt5.12 2.詳細代碼 QComboB…

中小企業和數智化的距離,只差一塊華為IdeaHub

每次談及中小企業數智化的話題&#xff0c;被提到最多的總是“三不”難題&#xff0c;即不想轉、不敢轉、不會轉。 為了破解這一困局&#xff0c;政府多次在工作報告中提到“深入開展中小企業數字化賦能專項行動”&#xff0c;并在各地為中小企業創新提供政策支持。此外&#…

Android --- Kotlin學習之路:基礎語法學習筆記

------>可讀可寫變量 var name: String "Hello World";------>只讀變量 val name: String "Hello World"------>類型推斷 val name: String "Hello World" 可以寫成 val name "Hello World"------>基本數據類型 1…

MD5加密和注冊頁面的編寫

MD5加密 1.導入包 npm install --save ts-md5 2.使用方式 import { Md5 } from ts-md5; //md5加密后的密碼 const md5PwdMd5.hashStr("123456").toUpperCase(); 遇見的問題及用到的技術 注冊頁面 register.vue代碼 <template><div class"wappe…

從零開始學習嵌入式----Linux 命令行,常用命令速記指南

目錄 一、文件操作 二、文本操作 三、系統管理 四、網絡操作 五、其他常用命令 六、學習建議 在 Linux 世界里&#xff0c;命令行就像一把瑞士軍刀&#xff0c;掌握了它&#xff0c;你就能游刃有余地操控整個系統。但面對茫茫多的命令&#xff0c;新手往往會感到無所適從…

關于Python中的字典你所不知道的七個技巧

01 引言 Python是我最喜歡的編程語言之一&#xff0c;它向來以其簡單性、多功能性和可讀性而聞名。 字典作為Python中最常使用的數據類型&#xff0c;大家幾乎每個人都或多或少在項目中使用過字典&#xff0c;但是字典里有一些潛在的技巧可能并不是每個同學都會用到。 在本文…

相同含義但不同類型字段作為join條件時注意事項

假設表A和表B中都有表示學號的stu_id字段&#xff0c;但該字段在表A和表B中類型分別為bigint和string。當直接通過該字段進行join時&#xff0c;一般情況下可以得到我們預期的結果。 select a.stu_id from a as r join b as l on r.stu_id l.stu_id 但是如果學號長度較長的…

【UE5.1 角色練習】16-槍械射擊——瞄準

目錄 效果 步驟 一、瞄準時拉近攝像機位置 二、瞄準偏移 三、向指定方向射擊 四、連發 效果 步驟 一、瞄準時拉近攝像機位置 打開角色藍圖&#xff0c;在事件圖表中添加如下節點&#xff0c;當進入射擊狀態時設置目標臂長度為300&#xff0c;從而拉近視角。 但是這樣切…

勇攀新高峰|暴雨信息召開2024年中述職工作會議

7月8日至9日&#xff0c;暴雨信息召開2024年中述職工作會議&#xff0c;總結回顧了上半年的成績和不足&#xff0c;本次會議采用線上線下的方式舉行&#xff0c;公司各部門管理人員、前臺市場營銷人員參加述職&#xff0c;公司領導班子出席會議。 本次述職采取了現場匯報點評的…

關于宏v4l2_subdev_call的拆解

struct v4l2_subdev *sd結構體 struct v4l2_subdev { #if defined(CONFIG_MEDIA_CONTROLLER)struct media_entity entity; #endifstruct list_head list;struct module *owner;bool owner_v4l2_dev;u32 flags;struct v4l2_device *v4l2_dev;const struct v4l2_subdev_ops *op…