深度優(yōu)先搜索(dfs)例題總結(jié)

<font size="6px">
一、部分和問題</font>

題目描述:給定整數(shù)序列a1葬项,a2泞当,.....,an民珍,判斷是否可以從中選出若干數(shù)襟士,使他們的和恰好為k盗飒。
???????1<=n<=20
???????-10^8 <= ai <= 10^8
???????-10^8 <= k <= 10^8
樣例:
輸入
???????n=4
???????a={1,2,4,7}
???????k=13
輸出
???????Yes (13=2+4+7)


思路分析:這道題目首先按照題目進(jìn)行輸入。之后調(diào)用dfs1()方法陋桂,將數(shù)組箩兽,k,以及數(shù)組的首位置傳過去(作為0狀態(tài))章喉。然后開始遍歷位置,每一個位置都面臨兩種選擇身坐,第一種選擇是取這個位置的值秸脱,第二種選擇是不取這個位置的值。第一種選擇不取這個位置的值就去查看下一個位置的值部蛇,就對應(yīng)代碼dfs1(arr,k,current+1);摊唇,只有狀態(tài)加一,其余不變涯鲁。第二種選擇取這個位置的值巷查,就將該位置的值存入list中,并獲得index抹腿。然后調(diào)用代碼dfs1(arr,k-arr[current],current+1);岛请,可見k的值減去該位置的值,同樣狀態(tài)+1警绩。這題有一個必要的點(diǎn)是要記得回溯崇败,如果這條路走不通,要回溯到原來的狀態(tài)肩祥,就是將該位置的值在list中刪除后室,對應(yīng)代碼list.remove(index); 。最后一步就是確定出口混狠,當(dāng)k等于0時就輸出結(jié)果岸霹。當(dāng)k<0或者current==arr.length時說明這條路走不通,返回繼續(xù)尋找其他路徑将饺。

static int kk;
    static ArrayList<Integer> list=new ArrayList<>();           //存放計(jì)算過程
    //部分和問題
    public static void main(String[] args) {
        Scanner reader=new Scanner(System.in);
        
        int n=reader.nextInt();
        int[] arr=new int[n];
        for(int i=0;i<arr.length;i++) {                         //按題目輸入
            arr[i]=reader.nextInt();
        }
        kk=reader.nextInt();
        
        dfs1(arr,kk,0);                                         //調(diào)用深度優(yōu)先搜索

    }
    
    public static void dfs1(int[] arr,int k,int current) {
        if(k==0) {                                              //出口
            System.out.print("Yes (");
            System.out.print(kk+"=");
            for(int j=0;j<list.size();j++) {
                if(j==list.size()-1) {
                    System.out.print(list.get(j));
                }else {
                    System.out.print(list.get(j)+"+");
                }
            }
            System.out.println(")");
            System.exit(0);
        }
        if(current==arr.length||k<0) {                          //沒有找到答案
            return;
        }
        
        dfs1(arr,k,current+1);                                  //第一種情況贡避,不取,狀態(tài)+1
        
        list.add(arr[current]);                                 //將該狀態(tài)的數(shù)字存入list中
        int index=list.size()-1;                                //記錄位置予弧,方便回溯
        dfs1(arr,k-arr[current],current+1);                     //第二種情況贸桶,取,狀態(tài)+1
        list.remove(index);                                     //回溯
    }

<font size="6px">
二桌肴、水洼數(shù)目問題</font>

題目描述:有一個大小為NM的園子皇筛,雨后積起了水,八連通的積水被認(rèn)為是連接在一起的坠七。請求出園子里總共有多少水洼水醋?(八連通值得是下圖中相對W的*的部分)
???????***
???????*W*
???????***
限制條件:
???????N,M<=100
樣例:
輸入
???????N=10,M=12
園子如下圖:

vfew

輸出
???????3
*

思路分析:這道題目首先按照題目進(jìn)行輸入,將園子存入字符數(shù)組中旗笔。之后循環(huán)遍歷園子,查看那個點(diǎn)位存在水洼拄踪,就調(diào)用dfs2()方法去清除與該點(diǎn)連通的水洼蝇恶。方法中,以(i,j)為起點(diǎn)惶桐,有8個位置可以行走撮弧,但是不能重復(fù)上一層,故要先清除(i姚糊,j)位上的水洼贿衍。然后8個位置分為就是k=-1,0救恨,1贸辈,j=-1,0肠槽,1.然后要排除k=0擎淤,j=0的情況,并且注意越界秸仙。如果(i+k嘴拢,j+q)存在連通水洼,則調(diào)用方法清除水洼寂纪。最后輸出結(jié)果

// 水洼數(shù)目問題
    static char[][] arr;                            //字符數(shù)組炊汤,存放園子
    static int N, M;    
    static int count=0;                             //記錄水洼數(shù)目                            
    
    public static void main(String[] args) {
        Scanner reader = new Scanner(System.in);
        N = reader.nextInt();
        M = reader.nextInt();
        arr = new char[N][];
        
        for (int i = 0; i < N; i++) {
            arr[i] = reader.next().toCharArray();   //初始化園子
        }
        
        for (int i = 0; i < N; i++) {               //循環(huán)遍歷園子的每一個位置  
            for (int j = 0; j < M; j++) {
                if (arr[i][j] == 'W') {             //如果是W
                    dfs2(i, j);                     //調(diào)用函數(shù),清除水洼
                    count++;                        //水洼數(shù)+1
                }
            }
        }
        System.out.println(count);
    }

    private static void dfs2(int i, int j) {
        arr[i][j] = '.';                            //清除該水洼
        
        //遍歷查詢與該點(diǎn)連通的水洼
        for (int k = -1; k < 2; k++) {              //-1弊攘,0抢腐,1        
            for (int q = -1; q < 2; q++) {          //-1,0襟交,1    
                if (k == q && q == 0) {
                    continue;
                }
                if (i + k >= 0 && j + q >= 0 && i + k <= N - 1 && j + q <= M - 1) {         //限定范圍
                    if (arr[i + k][j + q] == 'W') {         //如果存在連通的水洼
                        dfs2(i + k, j + q);                 //遞歸調(diào)用迈倍,清除水洼
                    }

                }
            }
        }
    }

<font size="6px">
三、n皇后問題</font>

題目描述:請?jiān)O(shè)計(jì)一種算法捣域,解決著名的n皇后問題啼染。這里的n皇后問題指在一個nn的棋盤上放置n個棋子,使得每行每列和每條對角線上都只有一個棋子焕梅,求其擺放的方法數(shù)迹鹅。
給定一個int n,請返回方法數(shù)贞言,保證n小于等于15
*

思路分析:這道題目首先按照題目進(jìn)行輸入,創(chuàng)建一個整形數(shù)組斜棚,用來放每一行皇后的位置,調(diào)用dfs3()方法,從第0行開始遍歷弟蚀。因?yàn)橛衝行蚤霞,要放n個皇后所以肯定是每行一個皇后,故for (int i = 0; i < n; i++)用來遍歷每一行中的每一個位置义钉,for (int j = 0; j < row; j++)用來遍歷數(shù)組中之前每一行的皇后的位置昧绣。然后對(row,i)位置判斷是否能放皇后捶闸,如果不能放夜畴,就置judge為false。判斷的條件主要有三個删壮。1贪绘、同一列上不能有多個皇后。2醉锅、正對角線上不能有多個皇后(正對角線上x和y之和相等)3、反對角線上不能有多個皇后(反對角線上y-x的差相等)发绢。如果judge為true硬耍,就將該位置存入整形數(shù)組,遞歸調(diào)用下一行边酒。如果方法無法進(jìn)行下去经柴,就要回溯。最后要設(shè)置出口墩朦。

//n皇后問題
    static int[] arr;                                       // 整形數(shù)組坯认,用來存放每一行皇后的位置
    static int count;                                       // 記錄有多少種解法

    public static void main(String[] args) {
        Scanner reader = new Scanner(System.in);
        int n = reader.nextInt();
        arr = new int[n];

        dfs3(n, 0);                                         // 調(diào)用深度優(yōu)先搜索

        System.out.println(count); // 打印結(jié)果
    }

    private static void dfs3(int n, int row) {
        if (row == n) {                                     //出口
            count++;
            return;
        }
        for (int i = 0; i < n; i++) {                       //遍歷每一行中的每個位置
            
            boolean judge = true;                           //初始化
            
            for (int j = 0; j < row; j++) {                 //遍歷row行以前的皇后的
                
                if (arr[j] == i || row + i == j + arr[j] || i - row == arr[j] - j) {    //判定該位置是否能放皇后
                    judge = false;                          //不能放皇后
                }
                
            }
            if (judge) {                                    //如果judge為true
                arr[row] = i;                               //將row行i號位放置皇后
                dfs3(n, row + 1);                           //遞歸調(diào)用下一行的皇后
                arr[row] = 0;                               //方法不成功,回溯
            }
        }
    }

<font size="6px">
四氓涣、素?cái)?shù)環(huán)問題</font>

題目描述:對于正整數(shù)n牛哺,對1~n進(jìn)行排列,使得相鄰兩個數(shù)之和均為素?cái)?shù)劳吠,輸出時從整數(shù)1開始引润,逆時針排列。同一個環(huán)應(yīng)恰好輸出一次
n<=16
如輸入:6
輸出:
1 4 3 2 5 6
1 6 5 2 3 4

思路分析:這道題目首先按照題目進(jìn)行輸入,創(chuàng)建一個整形數(shù)組痒玩,用來存放素?cái)?shù)環(huán)每一個位置的數(shù)字淳附。首先將1存入數(shù)組,然后調(diào)用dfs4()方法蠢古。for (int i = 1; i < n + 1; i++)嘗試將每一個數(shù)字填入到數(shù)組中奴曙,然后for (int j = 0; j < count; j++)循環(huán)遍歷是否數(shù)組中已經(jīng)存在這個數(shù)。如果不是草讶,接著判斷相鄰兩個數(shù)之和是否為素?cái)?shù)洽糟,如果是素?cái)?shù),遞歸調(diào)用下一個數(shù),將本次循環(huán)的數(shù)傳給下一次循環(huán)脊框,以便判斷相鄰的數(shù)颁督。最后設(shè)置出口,要記得判斷最后一個數(shù)字和第一個數(shù)字能否形成素?cái)?shù)環(huán)浇雹,如果可以沉御,就輸出結(jié)果。

    // 素?cái)?shù)環(huán)問題
    static int[] arr;                                       //整形數(shù)組昭灵,存放每一個位置的值
    static int count;                                       //數(shù)組中的個數(shù)

    public static void main(String[] args) {
        Scanner reader = new Scanner(System.in);
        int n = reader.nextInt();
        arr = new int[n];
        
        arr[0] = 1;                                         //將1存入數(shù)組
        count++;
        
        dfs4(n, 1);                                         //調(diào)用深度優(yōu)先搜索
    }

    private static void dfs4(int n, int k) {
        if (count == n) {                                   //出口
            if (judgePrimeNumber(arr[0] + arr[n-1])) {      //判斷最后一個數(shù)字和第一個數(shù)字之和是不是素?cái)?shù)
                for (int i = 0; i < n ; i++) {
                    System.out.print(arr[i]);               //輸出
                }
                System.out.println();
            }
            return;
        }
        for (int i = 1; i < n + 1; i++) {                   //嘗試用每一個數(shù)加入到數(shù)組中
            boolean judge = true;
            for (int j = 0; j < count; j++) {               //判斷這個數(shù)是否已經(jīng)被選過
                if (i == arr[j]) {
                    judge = false;
                }
            }
            if (judge == true) {
                if (judgePrimeNumber(k+i)) {                //判斷相鄰的數(shù)之和是否為素?cái)?shù)
                    arr[count] = i;                         //添加到數(shù)組中
                    count++;
                    dfs4(n, i);                             //遞歸調(diào)用下一個數(shù)
                    count--;
                    arr[count] = i;                         //回溯

                }
            }
        }

    }
    public static boolean judgePrimeNumber(int k) {          //判斷是否為素?cái)?shù)
        int q;
        for (q = 2; q < k; q++) {
            if (k % q == 0) {
                return false;
            }
        }
        return true;
    }

<font size="6px">
五吠裆、困難的串問題</font>

題目描述:如果一個字符串包含兩個相鄰的重復(fù)子串,則稱它為容易的串烂完,其他的串稱為困難的串试疙。
如:BB,ADCDACABCAB,ABCDABCD都是容易的串,D,DC,ADBAB,CBABCBA都是困難的抠蚣。
輸入正整數(shù)n祝旷,L,輸出由前L個字符組成的嘶窄,字典序第n小的困難的串怀跛。
例如,當(dāng)L=3時柄冲,前7個困難的串分別為:
A,AB,ABA,ABAC,ABACA,ABACAB,ABACABA
n指定為4的話吻谋,輸出ABAC

思路分析:這道題目首先按照題目進(jìn)行輸入,創(chuàng)建一個count用來存放第幾個现横。調(diào)用dfs5()方法漓拾。按照字典序遍歷,然后調(diào)用isHard()方法判斷是否把i加進(jìn)去也構(gòu)成苦難的串戒祠,如果成立骇两,就將i添加到prefix的末尾,count++姜盈,繼續(xù)遞歸調(diào)用脯颜,直到最后輸出。判斷苦難的串的方法贩据,是從后往前遍歷栋操。

    //困難的串
    static int L,n;                                     
    static int count=0;                                     //用來記錄第幾個
    public static void main(String[] args) {
        Scanner reader=new Scanner(System.in);
        n=reader.nextInt();
        L=reader.nextInt();
        dfs5("");                                           //調(diào)用深度優(yōu)先搜索
    }
    private static void dfs5(String prefix) {
        for(int i='A';i<='A'+L+1;i++) {                     //按照字典序遍歷
            if(isHard(prefix,i)) {                          //判斷將i加進(jìn)字符串中,是否還構(gòu)成困難的串
                String x=prefix+i;                          //將i加入字符串中
                count++;
                if(count==n) {                              //出口
                    System.out.println(x);
                    System.exit(0);
                }
                dfs5(x);                                    //遞歸調(diào)用饱亮,繼續(xù)尋找
            }
        }
        
    }
    private static boolean isHard(String prefix, int i) {    //判斷將i加進(jìn)字符串中矾芙,是否還構(gòu)成困難的串
        int cnt=0;
        for(int j=prefix.length()-1;j>=0;j-=2) {             //從末至尾判斷是否是苦難的串
            String x1=prefix.substring(j,j+cnt+1);
            String x2=prefix.substring(j+cnt+1)+i;
            if(x1.equals(x2)) {                              //是否相同,則為容易的串
                return false;
            }
            cnt++;
        }
        return true;
    }
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末近上,一起剝皮案震驚了整個濱河市剔宪,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖葱绒,帶你破解...
    沈念sama閱讀 216,591評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件感帅,死亡現(xiàn)場離奇詭異,居然都是意外死亡地淀,警方通過查閱死者的電腦和手機(jī)失球,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,448評論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來帮毁,“玉大人实苞,你說我怎么就攤上這事×揖危” “怎么了黔牵?”我有些...
    開封第一講書人閱讀 162,823評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長爷肝。 經(jīng)常有香客問我猾浦,道長,這世上最難降的妖魔是什么灯抛? 我笑而不...
    開封第一講書人閱讀 58,204評論 1 292
  • 正文 為了忘掉前任金赦,我火速辦了婚禮,結(jié)果婚禮上牧愁,老公的妹妹穿的比我還像新娘素邪。我一直安慰自己外莲,他們只是感情好猪半,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,228評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著偷线,像睡著了一般磨确。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上声邦,一...
    開封第一講書人閱讀 51,190評論 1 299
  • 那天乏奥,我揣著相機(jī)與錄音,去河邊找鬼亥曹。 笑死邓了,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的媳瞪。 我是一名探鬼主播骗炉,決...
    沈念sama閱讀 40,078評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼蛇受!你這毒婦竟也來了句葵?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,923評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎乍丈,沒想到半個月后剂碴,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,334評論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡忆矛,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,550評論 2 333
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了叼屠。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,727評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖挑宠,靈堂內(nèi)的尸體忽然破棺而出各淀,到底是詐尸還是另有隱情,我是刑警寧澤奴璃,帶...
    沈念sama閱讀 35,428評論 5 343
  • 正文 年R本政府宣布唱星,位于F島的核電站攒盈,受9級特大地震影響仑濒,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜喉酌,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,022評論 3 326
  • 文/蒙蒙 一纪铺、第九天 我趴在偏房一處隱蔽的房頂上張望突诬。 院中可真熱鬧,春花似錦蔬捷、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,672評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽喉镰。三九已至生真,卻和暖如春蚜厉,著一層夾襖步出監(jiān)牢的瞬間术瓮,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,826評論 1 269
  • 我被黑心中介騙來泰國打工游昼, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人尝蠕。 一個月前我還...
    沈念sama閱讀 47,734評論 2 368
  • 正文 我出身青樓烘豌,卻偏偏與公主長得像廊佩,于是被迫代替她去往敵國和親标锄。 傳聞我的和親對象是個殘疾皇子践剂,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,619評論 2 354

推薦閱讀更多精彩內(nèi)容