藍橋杯學習-13回溯

13回溯

一、回溯1

例題1–遞歸實現排列型枚舉-藍橋19684

1.遞歸可以解決不定次數的循環問題
2.使用數組來標記數字是否被選過

image-20250318115513224

image-20250317223817174

image-20250317224356020

import java.util.Scanner;public class Main {static int n;static boolean[] st = new boolean[10];  //判斷數字是否被選過static int[] path = new int[10];  //存儲排列組合//遞歸程序public static void dfs(int u){if(u > n){//遞歸結束的條件,遞歸結束就輸出結果。(但這里其實是針對每一次的排序而言)for (int i = 1; i <= n; i++) {System.out.print(path[i] + " ");}System.out.println();return;}//遞歸--循環排列組合for (int i = 1; i <= n ; i++) {if(st[i]) continue;st[i] = true;//選中path[u] = i;  //記錄dfs(u + 1);  //下一個數的循環st[i] = false;  //解除}}public static void main(String[] args) {Scanner sc = new Scanner(System.in);n = sc.nextInt();dfs(1);
/*        for (int i = 1; i <= n ; i++) {st[i] = true;for (int j = 1; j <= n ; j++) {
//                if(j == i) continue;if(st[j]) continue;st[j] = true;for (int k = 1; k <= n ; k++) {
//                    if (k == i || k ==j) continue;if(st[k]) continue;System.out.println(i+ "," + j + "," + k);}st[j] = false;}st[i] = false;}*/}
}

*特別注意!!!

結果對但是沒有通過用例,原因是輸出的格式問題!各個數之間要用空格隔開!這點特別需要注意。

例題2–串變換藍橋4360

對k個操作進行全排列。以及k--的排列,直到可以變為T串,或循環到最后都變不了

例題3–帶分數藍橋208

回溯+枚舉

思路,1-9出現且只出現1次,進行9的全排列,把9個數的所有組合排列出來,再把加號和除號放進去,看看哪些符合條件
import java.util.*;public class Main {static int N;static int count = 0;//static List<String> permutations = new ArrayList<>();public static void main(String[] args) {Scanner sc = new Scanner(System.in);N = sc.nextInt();sc.close();// 生成1~9的所有排列permute("123456789", 0, 8);System.out.println(count);}// 生成全排列public static void permute(String str, int l, int r) {if (l == r) {//permutations.add(str);check(str);} else {for (int i = l; i <= r; i++) {str = swap(str, l, i);permute(str, l + 1, r);str = swap(str, l, i); // 回溯}}}// 檢查所有的加號和除號位置public static void check(String str) {for (int i = 1; i <= 7; i++) {  // 加號位置,要大于0for (int j = i + 1; j <= 8; j++) {  // 除號位置,在加號的右邊int A = Integer.parseInt(str.substring(0, i));int B = Integer.parseInt(str.substring(i, j));int C = Integer.parseInt(str.substring(j));// 避免除0錯誤if (C == 0) continue;// 判斷是否符合 A + B / C = Nif (A + (double) B / C == N) {count++;}}}}// 字符串交換工具方法public static String swap(String str, int i, int j) {char[] charArray = str.toCharArray();char temp = charArray[i];charArray[i] = charArray[j];charArray[j] = temp;return new String(charArray);}
}
1234
1243
1324
1342
1432
1423
2134
2143
2314
2341
2431
2413
3214
3241
3124
3142
3412
3421
4231
4213
4321
4312
4132
4123

理解回溯中的關鍵操作

str = swap(str, l, i);
  • 做選擇:交換當前元素和 i 位置的元素,相當于嘗試將 i 放在當前的位置。
permute(str, l + 1, r);
  • 遞歸調用:繼續處理后面的數字,進入下一層。
str = swap(str, l, i);
  • 撤銷選擇:把字符串恢復到原來的狀態,確保不影響下一次的嘗試。
  • 這是 回溯的精髓:探索完一條路徑后,將狀態恢復,以便繼續探索其他路徑。

建議:用樹狀圖畫出回溯的執行過程,一步步理解狀態的變化。

幾道回溯小題

二、回溯2

例題–N皇后問題藍橋1508

題目要求也不允許處在與棋盤邊框成 45 角的斜線上。(注意與棋盤邊框)

主對角線

image-20250320191048400

副對角線

image-20250320191232638

暴力做法

假設n=4,進行4次循環的嵌套,每一次代表的是每一行棋子的位置。
public class Main {static int N = 30;//行row,列col,主對角線zhu,副對角線fustatic boolean[] row = new boolean[N];static boolean[] col = new boolean[N];static boolean[] zhu = new boolean[N];static boolean[] fu = new boolean[N];public static void main(String[] args){int ans = 0;//記錄//一個for表示一行for (int i = 1; i <= N; i++) {//嘗試第1個棋子int x1 = 1,y1 = i;//行//列//被選中了就為truerow[x1] = true;col[y1] = true;zhu[N - y1 + x1] = true;fu[x1 + y1] = true;for (int j = 1; j <= N; j++) {//嘗試第2個棋子int x2 = 2,y2 = j;//行//列//不符合規則的就跳過if(row[x2] || col[y2] || zhu[N - y2 + x2] || fu[x2 + y2]) continue;//被選中了就為truerow[x2] = true;col[y2] = true;zhu[N - y2 + x2] = true;fu[x2 + y2] = true;for (int k = 1; k <= N; k++) {//嘗試第3個棋子//同樣for (int l = 1; l <= N; l++) {//嘗試第4個棋子//同樣,順便ans加加}}//結束要釋放//回溯row[x2] = false;col[y2] = false;zhu[N - y2 + x2] = false;fu[x2 + y2] = false;}//結束要釋放//回溯row[x1] = false;col[y1] = false;zhu[N - y1 + x1] = false;fu[x1 + y1] = false;}}
}

其實上面的row數組是沒必要的,因為循環的就是行數,按行數來的。

dfs遞歸做法

import java.util.Scanner;//TIP To <b>Run</b> code, press <shortcut actionId="Run"/> or
// click the <icon src="AllIcons.Actions.Execute"/> icon in the gutter.
public class Main {static int ans;static int n;static int N = 30;//行row,列col,主對角線zhu,副對角線fu//static boolean[] row = new boolean[N];static boolean[] col = new boolean[N];static boolean[] zhu = new boolean[N];static boolean[] fu = new boolean[N];//遞歸函數public static void dfs(int u){if(u > n){//循環到最后ans++;return;}for (int i = 1; i <= n; i++) {//這表示每一行循環每一列,因此i表示的是列數,u表示的是行數//首先判斷是否被占用if(col[i] || zhu[n - i + u] || fu[u + i])  continue;//選中一個數col[i] = true;zhu[n - i + u] = true;fu[u + i] = true;//遞歸下一行dfs(u + 1);//回溯col[i] = false;zhu[n - i + u] = false;fu[u + i] = false;}}//主邏輯函數public static void solve(){//輸入NScanner sc = new Scanner(System.in);n = sc.nextInt();//調用dfs(1);System.out.println(ans);}public static void main(String[] args) {solve();}
}
學到的知識點:
1.難點:本題要求不能在同一行,同一列和與棋盤邊框成45度角。
45度角這個需要找規律。
把這些情況都轉換為設為一個布爾數組,來判斷是否被放置。true--被放置,false--沒有。
2.學習到的遞歸知識:
首先,設n為4,進行一個暴力的做法。
就是遍歷每一行,對于每一行,判斷某個位置是否符合條件(1中的條件)。
符合條件后,設定其被放置,進行下一層遍歷。否則continue。
對于一次找到合法的放置位置后,需要將位置進行釋放--這就是回溯。因此,將暴力的做法轉為遞歸,就容易了。
找到一個合法的放置位置(u>x后),ans++;
遞歸函數中,為每一行的遍歷。
一行遍歷完后進行下一行的遞歸(dfs(u + 1));
下面幾行回溯。

寫完代碼看完視頻又忘記思路,不好說。只可意會。

三、回溯3-子集枚舉(遞歸實現指數型枚舉)

一旦涉及選與不選,刪和不刪,留和不留-->兩種狀態-->就要想到子集枚舉

image-20250320215536930

例題1–遞歸實現指數型枚舉19685

image-20250320221938056

其實看不懂這個題目,好奇怪的題目。根據老師的解析來寫。
大致理解為從1-n中,輸出所有的組合數就對了。
我知道了,就是要按照題目的要求來,要先判斷0不選,再判斷1選。具體看代碼更了解。

暴力做法

假設n=3.

public class Main {static int[] st = new int[10];//主邏輯函數public static void solve(){int n = 3;for (int i = 0; i <=1; i++) {//表示選或不選st[1] = i;for (int j = 0; j <= 1; j++) {//表示選或不選st[2] = j;for (int k = 0; k <= 1; k++) {//表示選或不選st[3] = k;for (int l = 1; l <= 3; l++) {//選中的輸出if(st[l] == 1) System.out.print(l);}System.out.println();}}}}public static void main(String[] args) {solve();}
}

使用回溯dfs來實現

image-20250321213009196

import java.util.Scanner;//TIP To <b>Run</b> code, press <shortcut actionId="Run"/> or
// click the <icon src="AllIcons.Actions.Execute"/> icon in the gutter.
public class Main {static int n;static int[] st = new int[20];//遞歸函數public static void dfs(int u){if(u > n){//一次結束,輸出結果for (int l = 1; l <= n; l++) {//選中的輸出if(st[l] == 1) System.out.print(l + " ");}System.out.println();return;//這里要返回,因為?}for (int i = 0; i <= 1; i++) {st[u] = i;dfs(u + 1);//下一個數選或不選}}//主邏輯函數public static void solve(){Scanner sc = new Scanner(System.in);n = sc.nextInt();dfs(1);
//        for (int i = 0; i <=1; i++) {//表示選或不選
//            st[1] = i;
//            for (int j = 0; j <= 1; j++) {//表示選或不選
//                st[2] = j;
//                for (int k = 0; k <= 1; k++) {//表示選或不選
//                    st[3] = k;
//                    for (int l = 1; l <= 3; l++) {
//                        //選中的輸出
//                        if(st[l] == 1) System.out.print(l);
//                    }
//                    System.out.println();
//                }
//            }
//        }}public static void main(String[] args) {solve();}
}
特別注意輸出的格式問題,空格或者逗號特別注意,總因為這個沒通過!!!

例題2–19880

例題3–蛋糕的美味值8664

package huisu;import java.util.Scanner;public class TasteCake {static int[] cake = new int[30];static int[] st = new int[30];static int n,k;static int max;//獲得最大的總和public static void getMax(){int sum = 0;for (int i = 1; i <= n; i++) {if(st[i] == 1){//被選中并且美味值小于ksum += cake[i];}}//結束后返回目前最大值if(sum < k){max = Math.max(sum,max);}}//遞歸public static void dfs(int u){//u表示第幾個蛋糕if(u > n){//表示n個蛋糕選與不選完了getMax();return;}for (int i = 0; i <= 1; i++) {//選與不選st[u] = i;dfs(u + 1);//下一個蛋糕}}//主邏輯函數public static void solve(){Scanner sc = new Scanner(System.in);//輸入n,kn = sc.nextInt();k = sc.nextInt();//輸入蛋糕的美味值for (int i = 1; i <= n; i++) {cake[i] = sc.nextInt();}//遞歸dfs(1);//輸出結果System.out.println(max);}public static void main(String[] args) {solve();}
}
注意:
一定要看清題目啊,看題目和觀察樣例。
這里是要選出的蛋糕的總值小于k,而不是選出的每一個小于k的。
我第一次寫理解為后面那一種,就錯了。
其實看樣例也能看出來。
題目真難理解。。。

例題4–luoguP1036

思想

老師說只需要思考最后兩層的遞歸,其他層的遞歸其實就和最后兩層一樣
對于選與不選的遞歸問題,事件復雜度都是2^n,對于n<=25的都可以運行

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

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

相關文章

【IDEA中配置Maven國內鏡像源】

1. 為什么需要配置國內鏡像源&#xff1f; 首先&#xff0c;Maven本身的工作原理是通過從倉庫中下載依賴包。而這些依賴通常來自于 Maven中央倉庫&#xff08;位于國外&#xff09;&#xff0c;由于網絡原因&#xff0c;我們在國內訪問這些遠程倉庫的速度比較慢&#xff0c;甚至…

【QA】觀察者模式在QT有哪些應用?

1. 信號與槽機制 Qt的**信號與槽&#xff08;Signals & Slots&#xff09;**是觀察者模式的典型實現&#xff0c;通過元對象系統&#xff08;Meta-Object System&#xff09;實現松耦合通信。 核心特點&#xff1a; 類型安全&#xff1a;編譯時檢查參數匹配跨線程支持&…

uniapp中的路由、本地存儲與網絡請求

navigator 在UniApp中&#xff0c;navigator 組件用于頁面跳轉和應用內導航。 基本使用 屬性&#xff1a; url: 需要跳轉的目標頁面路徑&#xff0c;路徑可以是相對路徑或絕對路徑。open-type: 跳轉的方式&#xff0c;默認為 navigateTo。其他可選值包括&#xff1a;redirec…

python3使用lxml解析xml時踩坑記錄

文章目錄 你的 XML 數據解析 XML----------------------------1. 獲取 mlt 根元素的屬性--------------------------------------------------------2. 獲取 chain 元素的屬性--------------------------------------------------------3. 獲取所有 property 的值-------------…

【DeepSeek 學c++】dynamic_cast 原理

用于向下轉化。 父類引用指向指類對象 假設父親是a, 子類是b. B* pb new B; 子類對象 A* pa 父類引用指向子類對象&#xff0c; 那么向上轉化 Apa pb 這個是自動完成的&#xff0c;隱式轉化&#xff0c;不需要dynamic_cast 向下轉化指的是 A pa new B。 這個是指向子類對象…

c++ 數組索引越界檢查

用 c 編寫了一些程序&#xff0c;發現 c 不會自動檢查數組的索引越界問題。有時候程序運行錯誤&#xff0c;提示的錯誤信息莫名其妙&#xff0c;但很可能是某個數組越界的問題。 例如&#xff1a; #include <iostream>int main() {double arr[5] {1.1, 2.2, 3.3, 4.4,…

Touch Diver:Weart為XR和機器人遙操作專屬設計的觸覺反饋動捕手套

在虛擬現實&#xff08;VR&#xff09;和擴展現實&#xff08;XR&#xff09;領域&#xff0c;觸覺反饋技術正逐漸成為提升沉浸感和交互體驗的重要因素。Weart作為這一領域的創新者&#xff0c;憑借其TouchDIVER Pro和TouchDIVER G1觸覺手套&#xff0c;為用戶帶來了高度逼真的…

基于deepseek的智能語音客服【第二講】后端異步接口調用封裝

本篇內容主要講前端請求&#xff08;不包含&#xff09;訪問后端服務接口&#xff0c;接口通過檢索知識庫&#xff0c;封裝提示詞&#xff0c;調用deepseek的&#xff0c;并返回給前端的全過程&#xff0c;非完整代碼&#xff0c;不可直接運行。 1.基于servlet封裝異步請求 為…

歸并排序的思路與實現

歸并排序主要是兩大模塊 分治 和 合并 即將已有序的子序列合并&#xff0c;得到完全有序的序列&#xff1b;即先使每個子序列有序&#xff0c;再使子序列段間有序。若將兩個有序表合并成一個有序表&#xff0c;稱為二路歸并 由于使用了新的數組 那么空間復雜度就為O(n) 但這…

Word中公式自動標號帶章節編號

&#xff08;1&#xff09;插入一行三列的表格&#xff0c;設置寬度分別為0.5&#xff0c;13.39和1.5&#xff0c;設置縱向居中&#xff0c;中間列居中對齊&#xff0c;最右側列靠右對齊&#xff0c;設置段落如下 &#xff08;2&#xff09;插入域代碼 【Word】利用域代碼快速實…

阿里云服務器環境部署 四 MySQL主從配置

安裝MySQL 導入mysql鏡像 docker load -i /opt/dockerinstall/mysql/mysql-8.1.0.tar docker run --privilegedtrue --name mysql8 --restartunless-stopped -e MYSQL_ROOT_PASSWORD123456 -p 3306:3306 -v /usr/local/mysql/logs:/var/log/mysql -v /usr/local/mysql/d…

[RH342]iscsi配置與排錯

[RH342]iscsi配置與排錯 1. 服務端配置1.1 安裝targetcli1.2 準備磁盤1.3 服務端配置1.4 防火墻配置 2. 客戶端配置2.1 安裝客戶端軟件2.2 配置客戶端2.3 連接登錄服務端2.4 掛載使用 3. 安全驗證擴展3.1 服務端3.2 客戶端 4. 常見的排錯點4.1 服務端常見錯誤4.2 客戶端常見錯誤…

服裝零售行業數字化時代的業務與IT轉型規劃P111(111頁PPT)(文末有下載方式)

服裝零售行業數字化時代的業務與IT轉型規劃P111 詳細資料請看本解讀文章的最后內容。 隨著數字化技術的迅猛發展&#xff0c;服裝零售行業正經歷著前所未有的變革。本文將對《服裝零售行業數字化時代的業務與IT轉型規劃P111》進行詳細解讀&#xff0c;探討未來幾年內該行業的…

基于javaweb的SSM+Maven寵物領養寵物商城流浪動物管理系統與實現(源碼+文檔+部署講解)

技術范圍&#xff1a;SpringBoot、Vue、SSM、HLMT、Jsp、PHP、Nodejs、Python、爬蟲、數據可視化、小程序、安卓app、大數據、物聯網、機器學習等設計與開發。 主要內容&#xff1a;免費功能設計、開題報告、任務書、中期檢查PPT、系統功能實現、代碼編寫、論文編寫和輔導、論…

PostgreSQL 數據庫中導入大量數據

在 PostgreSQL 數據庫中導入大量數據,可根據數據來源和格式選擇不同的方法。以下為你詳細介紹幾種常見的方式: 1. 使用 COPY 命令(適用于本地數據文件) COPY 命令是 PostgreSQL 內置的高效數據導入工具,適合處理本地的數據文件。 步驟 準備數據文件 確保你的數據文件格…

C++語法之命名空間二

A.h頭文件中代碼&#xff1a; namespace a {void 輸出(); }; A.cpp源文件中代碼&#xff1a; #include <iostream> #include "A.h" void a::輸出() {std::cout << "A.h里的輸出函數" << std::endl; } B.h頭文件中代碼&#xff1a; …

基于FPGA的DDS連續FFT 仿真驗證

基于FPGA的 DDS連續FFT 仿真驗證 1 摘要 本文聚焦 AMD LogiCORE IP Fast Fourier Transform (FFT) 核心,深入剖析其在 FPGA 設計中的應用。該 FFT 核心基于 Cooley - Tukey 算法,具備豐富特性,如支持多種數據精度、算術類型及靈活的運行時配置。文中詳細介紹了其架構選項、…

美團Leaf分布式ID生成器使用教程:號段模式與Snowflake模式詳解

引言 在分布式系統中&#xff0c;生成全局唯一ID是核心需求之一。美團開源的Leaf提供了兩種分布式ID生成方案&#xff1a;號段模式&#xff08;高可用、依賴數據庫&#xff09;和Snowflake模式&#xff08;高性能、去中心化&#xff09;。本文將手把手教你如何配置和使用這兩種…

Swift 并發任務的協作式取消

在 Swift 并發&#xff08;Swift Concurrency&#xff09;中&#xff0c;任務&#xff08;Task&#xff09;不會被強行終止&#xff0c;而是采用**協作式取消&#xff08;cooperative cancellation&#xff09;**機制。這意味著任務會被標記為“已取消”&#xff0c;但是否真正…

大數據(1.1)紐約出租車大數據分析實戰:從Hadoop到Azkaban的全鏈路解析與優化

目錄 一、背景與數據價值? ?二、技術選型與組件分工? ?三、數據準備與預處理? 四、實戰步驟詳解? ?1. 數據上傳至HDFS ?2. Hive數據建模與清洗? 4?.2.1 建表語句&#xff08;分區表按年份&#xff09;?&#xff1a; ?4?.2.2 數據清洗&#xff08;剔除無效…