專題 二分法:查找與判定

概念解釋

概述

? ? ? ? 二分法在算法競賽中一般有這么一個用途:在一個具有單調性的解空間中找到符合題意的一個可行解。下面解釋幾個專有名詞:

解空間

? ? ? ? 很簡單,就是可能存在解的邏輯區域。這個在算法入門時應提到。

可行解

? ? ? ? 符合題意的解

單調性

? ? ? ? 與數學中的基本是一回事。

算法分析

原理

? ? ? ? 就是數學中的逼近原理。通過計算機的高效計算,可以逐步靠近可行解;又由于解空間具有單調性,所以可以簡化枚舉的過程。簡單來講,二分是一種更高效的枚舉手段。

應用

? ? ? ? 我們主要是研究在整數域上的二分。

1.二分查找

? ? ? ? 在一個序列中查找某一個指定的元素,這可以通過二分查找來實現。下面給出一個例子:

? ? ? ? 給出一個整數序列?A?,這個序列有n?個元素。下有m?次詢問,每次會詢問一個整數,請回答該數是否在?A?中。如果否,請分別輸出大于或等于該數的第一個后繼,小于或等于該數的第一個前驅以及-1;如果這個數存在,輸出以上除-1之外并輸出這個數。

? ? ? ? 這很顯然如果樸素去求,時間復雜度會是O(mn)?的,在1e5及以上的規模下會TLE。下面考慮二分求解。

? ? ? ? 回憶概念,我們強調,要在一個單調的解空間中尋找答案。所以考慮對這個序列排序;時間復雜度為O(nlogn)??。?然后執行以下過程:

  • 將區間一分為二;
  • 維護區間的中間端點?mid?。記錄?a[mid]?的值。
  • 如果a[mid]\leq x?,收縮左端點,重復以上步驟;
  • 如果a[mid]\geq x?,收縮右端點,重復以上步驟;
  • 直到區間被收縮至只有一個元素,檢查這個元素是否是所求。

? ? ? ? 過程很簡單,時間復雜度也很低,為?O(log_{2}n)?。但是這里有很多的細節需要注意,筆者盡量把這些細節全部展示清楚。首先可以先看下面的參考程序,這里選擇結合代碼研究。

? ? ? ??取等問題

? ? ? ? 很簡單,總結出來就一句話:如果A中的元素跟?x?有可能取等,那么收縮區間時,區間端點與?mid?就取等;反之,不能取等(這時往往+1或者-1)。也就是相鄰,一邊是實心端點,一邊是空心端點。還可以這么看:如果取等,意味著?mid?處有可能會是答案,所以收縮區間時,區間端點可以等于?mid?。

? ? ? ? 劃分問題

? ? ? ? 也就是考慮?mid?的取值。通常有兩種:

????????mid=(l+r)>>1?

????????以及

????????mid=(l+r+1)>>1

? ? ? ? 區別是:

? ? ? ? 第一種的寫法不會取到?r?,第二種寫法不會取到?l?。進一步地,我們知道,第一種是向下取整,稱為左中位數;第二種向上取整,則是右中位數。我們可以利用這一性質處理無解的問題:設置最初區間分別為:?[0,n]?和?[1,n+1]?把一個越界的下標包括起來,如果最后停止在這個下標上,說明無解。當然,第一種適用于找后繼,第二種適用于找前驅。

? ? ? ? STL 函數

? ? ? ? 下面介紹兩個 STL 的函數,分別是 lower_bound(),upper_bound()。這兩個函數分別返回的是在一個單調遞增序列中第一個大于或等于某個數的后繼,以及第一個大于某數的后繼。同樣在下面給出手寫代碼。這里的關鍵就是上面說的劃分問題。

2.二分答案

? ? ? ? 這里主要是兩類問題,最大值最小化以及最小值最大化。也就是判定問題。我們一開始就說過,

???“?通過計算機的高效計算,可以逐步靠近可行解;又由于解空間具有單調性,所以可以簡化枚舉的過程。簡單來講,二分是一種更高效的枚舉手段。”

? ? ? ? 所以歸根結底還是二分查找。請記住:最優化問題往往等價于一個可行性問題的判定。進一步地,是在一個具有嚴格約束的情況下利用二分法枚舉出一個答案來。

? ? ? ? 這句話非常有信息量。我們會給出幾個等價的表述以及幾個例子深刻去理解。

? ? ? ? 有這么幾種表述:

? ? ? ? 建立一個定義域為解空間,值域為0或1的單調分段函數,在這個函數上二分查找分界點。

? ? ? ? 其實本質都是一回事。

? ? ? ? 下面給出幾個例子理解一下。

? ? ? ? 最小值最大化

? ? ? ? 例題:luogu.P2678 [NOIP 2015 提高組] 跳石頭

? ? ? ? 二分所求。找出約束:

“由于預算限制,組委會至多從起點和終點之間移走?M?塊巖石(不能移走起點和終點的巖石)。”

? ? ? ? 也就是說,M 是約束。這樣就容易設計check?函數:每次枚舉一個最小值,檢查是否合法。由于這個最小值是具有單調性的,所以可以考慮二分出這個最大值。?

????????最大值最小化

? ? ? ? 例題:luogu.P3853 [TJOI2007] 路標設置

? ? ? ? 二分所求。找出約束:

“以及最多可增設的路標數量”

? ? ? ? 也就是說,路標數量是約束。這樣就容易設計?check?函數:每次枚舉一個最大值,檢查是否合法。由于這個最大值是具有單調性的,所以可以考慮二分出這個最小值。?

參考程序

在單調遞增序列中查找?\geq x?的最小的元素

//
while(l<r)
{int mid=(l+r)>>1;if(a[mid]<=x) l=mid;else r=mid-1;
} 
return a[l];//a[l]==a[r]為終止條件

在單調遞增序列中查找?\leq x?的最小的元素

//
while(l<r)
{int mid=(l+r+1)>>1;if(a[mid]>=x) r=mid;else l=mid-1;
} 
return a[l];//a[l]==a[r]為終止條件

最小值最大化

//
#include<iostream>
using namespace std;
int d[50005];
int l,n,m;
bool check(int k)//我們要二分的是最短跳躍距離
{int last=0,ans=0;for(int i=1;i<=n+1;i++){if(d[last]+k>d[i]) ans++;else last=i;}return ans<=m;//是否滿足約束
}
int main()
{cin>>l>>n>>m;for(int i=1;i<=n;i++)cin>>d[i];d[n+1]=l;int le=0,ri=l*2;while(le<ri)//二分{int mid=(le+ri+1)>>1;if(check(mid)) le=mid;else ri=mid-1;}cout<<le;return 0;
}

最大值最小化

//
#include<cstdio>
using namespace std;
int d[100005];
int l,n,k;
bool check(int w)//現在就假設我這里的w就是最大值 
{int last=0,ans=0;for(int i=2;i<=n;i++){//while(d[i]>last+w) last+=w,ans++;//我們二分已經是最大距離,如果有比這還大的,那就是要增設 //last=d[i];ans+=(d[i]-d[i-1]-1)/w;}return ans<=k;
}
int main()
{ scanf("%d%d%d",&l,&n,&k);for(int i=1;i<=n;i++)scanf("%d",&d[i]);int le=1,ri=l;while(le<ri){int mid=(le+ri)>>1;if(check(mid)) ri=mid;else le=mid+1;}printf("%d",le);return 0;
}

細節實現

? ? ? ? 我們來總結一下二分答案的一般步驟:

  • 判斷是否解空間具有單調性——這保證了二分答案的正確性;
  • 找出約束條件——這保證了二分的定義域不是無窮的,也就是保證了最值,即解的存在;
  • 設計check函數,檢驗枚舉過程中的解是否合法;
  • 利用二分查找完成枚舉,得出答案。

? ? ? ? 由此看來,最優化問題在筆者看來不是“構造”出來的,而是真真切切枚舉出來的。在枚舉時,保證枚舉的元素是題目所要求的最大或最小(假設一定是最大/最小值),也就是把被枚舉對象當成一個常量,判斷是否符合約束。所以最優化是枚舉出來的,最大/最小值是約束出來的。

總結歸納

? ? ? ? 二分法的初步應用。日后會有多次更新。

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

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

相關文章

硬核電子工程:從硅片到系統的全棧實戰指南—— 融合電路理論、嵌入式開發與PCB設計的工程藝術

一、電路基礎&#xff1a;硬件設計的底層邏輯1.1 基爾霍夫定律的硬件實現// STM32驗證KVL定律&#xff08;ADC采樣法&#xff09; void verify_kvl() {ADC_Enable(ADC1); // 啟用ADCfloat Vr1 read_ADC(PA0) * 3.3 / 4096; // 讀取R1電壓float Vr2 read_ADC(PA1) * 3.3 / 4…

Linux網絡:序列化與反序列化

引入&#xff1a;面向字節流 TCP是面向字節流的&#xff0c;如果按照字節流來讀取信息&#xff0c;可能會出問題 比如客戶傳入“1100”&#xff0c;服務器讀入“11”&#xff0c;后面的00被當作下一條信息&#xff0c;這就出問題了 我們可以將多個信息合并為一個字符串 在發送信…

二、Spark 開發環境搭建 IDEA + Maven 及 WordCount 案例實戰

作者&#xff1a;IvanCodes 日期&#xff1a;2025年7月20日 專欄&#xff1a;Spark教程 本教程將從零開始&#xff0c;一步步指導您如何在 IntelliJ IDEA 中搭建一個基于 Maven 和 Scala 的 Spark 開發環境&#xff0c;并最終完成經典的 WordCount 案例。 一、創建 Maven 項目…

【python】算法實現1

實現一個動態規劃算法 def dynamic_programming_example(n: int) -> List[int]:"""動態規劃示例&#xff1a;計算斐波那契數列參數:- n: 斐波那契數列的項數返回:- List[int]: 斐波那契數列前n項"""if n < 0:return []elif n 1:return […

C++控制臺貪吃蛇開發:從0到1繪制游戲世界

資料合集下載鏈接: ??https://pan.quark.cn/s/472bbdfcd014? 本文將帶你一步步實現以下目標: 初始化游戲元素(邊界、蛇、食物)的數據。 繪制靜態的游戲邊界(墻)。 在指定位置顯示蛇和食物。 學習并使用Windows API來精確定位光標,實現“指哪打哪”的繪圖。 隱藏閃爍…

共享模式、社群與開源鏈動2+1模式AI智能名片S2B2C商城小程序的協同發展研究

摘要&#xff1a;本文深入探討了共享模式與社群之間的內在聯系&#xff0c;指出信用體系完善是共享模式前提&#xff0c;信任源于相同認知促使共享在社群中更易發生。同時&#xff0c;引入開源鏈動21模式AI智能名片S2B2C商城小程序這一新興元素&#xff0c;分析其在共享模式與社…

LeetCode 322. 零錢兌換 LeetCode 279.完全平方數 LeetCode 139.單詞拆分 多重背包基礎 56. 攜帶礦石資源

LeetCode 322. 零錢兌換 思路1&#xff1a; 回溯算法可以做&#xff0c;只要存儲數組的最小長度即可&#xff0c;但可能會超時。思路2: 相當于是求最大價值的相反面&#xff0c;另外一個物品可以使用多次&#xff0c;因此是個完全背包。因此這是個完全背包的求最小價值類型題…

JAVA面試寶典 -《Elasticsearch 深度調優實戰》

文章目錄一、引言&#xff1a;搜索引擎為啥越來越慢&#xff1f;1.1 典型業務場景性能瓶頸表現??&#xff1a;二、倒排索引壓縮&#xff1a;讓存儲與檢索更高效&#x1f9e0; 2.1倒排索引結構簡述&#x1f527; 2.2 壓縮算法三劍客? 調優建議三、分片策略&#xff1a;寫入性…

克魯斯焊接機器人保護氣省氣方案

在現代焊接工藝中&#xff0c;克魯斯焊接機器人扮演著至關重要的角色。隨著制造業對成本控制和可持續發展的日益重視&#xff0c;焊接過程中的保護氣省氣問題成為了焦點。WGFACS節氣裝置為克魯斯焊接機器人的保護氣省氣提供了一種創新且有效的解決方案。克魯斯焊接機器人以其高…

JavaEE——多線程中的哈希表

目錄前言1.HashTable2.ConcurrentHashMap總結前言 在使用多線程前&#xff0c;我們用HashMap類來創建哈希表&#xff0c;但這個類線程不安全&#xff0c;在這篇文章&#xff0c;我們將介紹多線程環境的哈希表&#xff0c;將會講述HashTable, HashMap, ConcurrentHashMap這三個…

MyBatis Plus SQL性能分析:從日志到優化的全流程實戰指南

引言 在Java開發的江湖里&#xff0c;MyBatis Plus&#xff08;MP&#xff09;早已是“效率利器”——它用極簡的API封裝了CRUD操作&#xff0c;讓開發者從重復的SQL編寫中解放出來。但隨著項目數據量從“萬級”躍升至“十萬級”“百萬級”&#xff0c;一個尷尬的現實逐漸浮現&…

備忘錄設計模式

備忘錄模式&#xff08;Memento Pattern&#xff09;是一種行為設計模式&#xff0c;用于捕獲對象的內部狀態并在需要時恢復該狀態&#xff0c;同時不破壞對象的封裝性。它適用于需要實現撤銷/重做、歷史記錄或狀態快照的場景。核心組件Originator&#xff08;原發器&#xff0…

【世紀龍科技】智能網聯汽車環境感知系統教學難題的創新實踐?

在職業院校智能網聯汽車專業教學中&#xff0c;環境感知系統的教學長期面臨三大核心挑戰&#xff1a;設備成本高昂導致實訓資源不足、抽象原理難以直觀呈現、傳統教學模式難以滿足產業需求。如何讓學生在有限的教學條件下&#xff0c;深入理解激光雷達、毫米波雷達等核心部件的…

ES vs Milvus vs PG vector :LLM時代的向量數據庫選型指南

互聯網時代&#xff0c;關系型數據庫為王。相應的&#xff0c;我們的檢索方式也是精確匹配查詢為主——查找特定的用戶ID、商品編號或訂單狀態。但AI時代&#xff0c;語義檢索成為常態&#xff0c;向量數據庫成為搜索推薦系統&#xff0c;大模型RAG落地&#xff0c;自動駕駛數據…

磁盤陣列技術的功能與分類

磁盤陣列技術 磁盤陣列是由多臺磁盤存儲器組成的一個快速、大容量、高可靠的外存子系統。現在常見的磁盤陣列稱為廉價冗余磁盤陣列&#xff08;Redundant Array of Independent Disk,RAID)。目前&#xff0c;常見的 RAID 如下所示。 廉價冗余磁盤陣列 RAID級別 RAID-0是一種不具…

SpringMVC核心注解:@RequestMapping詳解

概述RequestMapping是SpringMVC中最核心的注解之一&#xff0c;用于將HTTP請求映射到MVC和REST控制器的處理方法上。基本功能RequestMapping主要用于&#xff1a;映射URL到控制器類或方法定義請求方法類型&#xff08;GET、POST等&#xff09;定義請求參數、請求頭等條件使用位…

【雜談】硬件工程師怎么用好AI工具做失效分析

最近被派到國外出差了&#xff0c;工作任務比較重&#xff0c;所以更新的頻率比較低。但在出差工作的過程中&#xff0c;我發現在失效分析時&#xff0c;有相當多的時間做的是比較重復的工作。比如失效分析肯定要一些證據如圖片、視頻。當我們做多臺設備的失效分析時&#xff0…

MyBatis詳解以及在IDEA中的開發

MyBatis概述 MyBatis是一個優秀的持久層框架&#xff0c;它支持定制化SQL、存儲過程以及高級映射。MyBatis避免了幾乎所有的JDBC代碼和手動設置參數以及獲取結果集的過程。 核心特點 優勢&#xff1a; SQL語句與Java代碼分離&#xff0c;便于維護支持動態SQL&#xff0c;靈活性…

LangGraph教程6:LangGraph工作流人機交互

文章目錄 Human-in-the-loop(人機交互) interrupt Warning Human-in-the-loop(人機交互) 人機交互(或稱“在循環中”)工作流將人類輸入整合到自動化過程中,在關鍵階段允許決策、驗證或修正。這在基于 LLM 的應用中尤其有用,因為基礎模型可能會產生偶爾的不準確性。在合規、…

Linux部署Milvus數據庫及Attu UI工具完全指南

一、準備工作1.1 環境要求操作系統&#xff1a;Ubuntu 20.04/Debian 11/CentOS 7硬件配置&#xff1a;至少8GB內存&#xff0c;4核CPU&#xff0c;50GB磁盤空間網絡要求&#xff1a;可訪問互聯網&#xff08;用于拉取Docker鏡像&#xff09;1.2 安裝Docker和Docker Compose1.2.…