算法學習4_搜索

深度優(yōu)先搜索- 不撞南墻不回頭
深度優(yōu)先搜索屬于圖算法的一種士修,英文縮寫為DFS即Depth First Search.其過程簡要來說是對每一個可能的分支路徑深入到不能再深入為止温兼,而且每個節(jié)點只能訪問一次.

下圖是一個無向圖以舒,如果我們從A點發(fā)起深度優(yōu)先搜索(以下的訪問次序并不是唯一的融师,第二個點既可以是B也可以是C,D)焚虱,則我們可能得到如下的一個訪問過程:A->B->E(沒有路了堰燎!回溯到A)->C->F->H->G->D(沒有路楣责,最終回溯到A,A也沒有未訪問的相鄰節(jié)點,本次搜索結束).

060828381f30e924b08eba2e4c086e061d95f782.jpg

簡要說明深度優(yōu)先搜索的特點:每次深度優(yōu)先搜索的結果必然是圖的一個連通分量.深度優(yōu)先搜索可以從多點發(fā)起.如果將每個節(jié)點在深度優(yōu)先搜索過程中的"結束時間"排序(具體做法是創(chuàng)建一個list坯台,然后在每個節(jié)點的相鄰節(jié)點都已被訪問的情況下炬丸,將該節(jié)點加入list結尾,然后逆轉(zhuǎn)整個鏈表)蜒蕾,則我們可以得到所謂的"拓撲排序",即topological sort.


題二稠炬、有九張(1-9)的撲克牌,放入九個盒子里面咪啡,使得 _ _ _ + _ _ _ = _ _ _ 成立首启,
現(xiàn)在使用深度優(yōu)先搜索優(yōu)化一下之前的方法,之前使用枚舉算法撤摸,時間復雜度太高

int a[10], book[10], n , total = 0;// C語言全局變量在沒有賦值的時候毅桃,默認為0
void dfsTwo(int step); // 深度優(yōu)先搜索
char* getDateTime(void);
int main(int argc, const char * argv[]) {
    char * time = getDateTime();
    printf("時間 ====%s \n",time);
    dfsTwo(1); // 首先在第一個盒子里面
    printf("總共有%d種方法",total/2);
    printf("時間 ====%s \n",time);
    getchar();
}
void dfsTwo(int step) // 深度優(yōu)先搜索
{
    int i = 0;
    if (step ==10) { // 如果是第十個個盒子,說明之前的九個盒子里面都是有撲克牌的
        // 判斷是否滿足等式  _ _ _ + _ _ _ = _ _ _
        
        if ((100*a[1] + 10*a[2] + a[3])+(100*a[4] + 10*a[5] + a[6])==(100*a[7] + 10*a[8] + a[9]) ) {
            // 如果滿足條件准夷, 解加一钥飞,并打印這個解
            total ++;
            printf("%d%d%d+%d%d%d=%d%d%d \n",a[1],a[2],a[3],a[4],a[5],a[6],a[7],a[8],a[9]);
        }
        return;
    }
    // 如果不是第十個盒子,哪應該放那張牌
    // 按照 1 - 9 的順序嘗試
    for (i = 1; i < 10; i ++) {
        
        // 判斷撲克牌是否在手中
        if (book[i] == 0) {
            
            // 開始使用手中的撲克牌
            a[step] = i;
            book[i] = 1;
            
            // 第step個盒子已經(jīng)放好了撲克牌衫嵌,走到下面一個盒子里面
            dfsTwo(step + 1);
            book[i] = 0; // 收回手中的牌读宙,才可以繼續(xù)操作
        }
    }
}

char* getDateTime()
{
    static char nowtime[20];
    time_t rawtime;
    struct tm* ltime;
    time(&rawtime);
    ltime = localtime(&rawtime);
    strftime(nowtime, 20, "%Y-%m-%d %H:%M:%S", ltime);
    return nowtime;
}

題三、深度優(yōu)先算法 最短路徑
看下列地圖楔绞,可以的到點a 到點b的最短距離
0 表示空地结闸, 1 表示障礙物 其中 a 和 b 也是在空地里面 ,求a(0酒朵,0) 到 b(3桦锄,2) 的最短距離 這里坐標為 (行,列)
5行 4列
0 0 1 0
0 0 0 0
0 0 1 0
0 1 0 0
0 0 0 1

int n3 ,m3 ,p3 ,q3,min3 = 99999999;
int a3[51][51], book3[51][51];
void dfsThree(int x,int y, int step);
char* getDateTime(void);

int main(int argc, const char * argv[]) {

    int i , j , startX ,startY;
    
    // 讀入n 和 m  n為行 m為列
    printf("請輸入 行 和列:");
    scanf("%d %d",&n3, &m3);
    
    // 讀入迷宮
    for (i = 0; i < n3; i ++ ) {
        printf("輸入迷宮:\n");
        for (j = 0; j < m3; j ++) {
            scanf("%d",&a3[i][j]);
        }
    }

    // 讀入 起點 和終點
    printf("輸入起點坐標");
    scanf("%d%d",&startX,&startY);  // 設置起點坐標為 (startX,startY)
    printf("輸入終點坐標");
    scanf("%d%d",&p3,&q3); // 設置終點坐標為 (p,q)
    
    
    // 從起點開始搜索
    book3[startX][startY] = 1; // 標記起點已經(jīng)在路徑上耻讽,防止再重復行走
    dfsThree(startX, startY, 0); // 第一個參數(shù) 為起點x 察纯,第二個為起點y 帕棉,第三個為初始化步數(shù)0
    
    printf("輸出最短步數(shù) 针肥,%d\n",min3);
    getchar();
}

// 得到 A點 到b點的最少步數(shù)
void dfsThree(int x,int y, int step) // 深度優(yōu)先搜索
{
    int next [4][2] = {
        {0,1},      // 向右走
        {1,0},      // 向下走
        {0,-1},     // 向左走
        {-1,0}      // 向上走
    };
    int tx = 0, ty = 0,k;
    // 判斷是否達到b點位置
    printf("x ==%d y ==%d  p3=== %d q3====%d \n",x,y,p3,q3);
    if (x == p3 && y == q3) {
       
        // 更新最小步數(shù)
        if (step < min3) {
             printf("輸出最短步數(shù) 饼记,%d\n",min3);
            min3 = step;
        }
        return;
    }
    
    // 枚舉四種走法
    for (k = 0; k < 4; k ++) {
        // 計算下一個點的坐標
        tx = x + next[k][0];  // x = 0 , y = 1 是因為是二維數(shù)組 [4][2] {0,1} 其中下標為0 為x 下標為1的為y。 k 數(shù)組是為長度為4
        ty = y + next[k][1];
        
        
        // 判斷是否越界
        if ( tx < 0 || tx > n3 || ty < 0 || ty > m3) {
            continue;
        }
        // 判斷改點是否是障礙物或者是已經(jīng)走過的點
        if (a3[tx][ty] == 0 && book3[tx][ty] == 0) { // 0 為空地 1 表示障礙物
            // 不是障礙物 或者已經(jīng)走過的點繼續(xù)
            book3[tx][ty] = 1; //標記這個點已經(jīng)走過
            dfsThree(tx, ty, step + 1);
            book3[tx][ty] = 0;
        }
    }
    return;
}

char* getDateTime()
{
    static char nowtime[20];
    time_t rawtime;
    struct tm* ltime;
    time(&rawtime);
    ltime = localtime(&rawtime);
    strftime(nowtime, 20, "%Y-%m-%d %H:%M:%S", ltime);
    return nowtime;
}

廣度優(yōu)先搜索 - 層層遞進
廣度優(yōu)先搜索算法(Breadth First Search)慰枕,又稱為"寬度優(yōu)先搜索"或"橫向優(yōu)先搜索"具则,簡稱BFS。

它的思想是:從圖中某頂點v出發(fā)具帮,在訪問了a之后依次訪問a的各個未曾訪問過的鄰接點博肋,然后分別從這些鄰接點出發(fā)依次訪問它們的鄰接點,并使得“先被訪問的頂點的鄰接點先于后被訪問的頂點的鄰接點被訪問蜂厅,直至圖中所有已被訪問的頂點的鄰接點都被訪問到匪凡。如果此時圖中尚有頂點未被訪問,則需要另選一個未曾被訪問過的頂點作為新的起始點掘猿,重復上述過程病游,直至圖中所有頂點都被訪問到為止。

題三稠通、廣度優(yōu)先算法 最短路徑
看下列地圖衬衬,可以的到點a 到點b的最短距離
0 表示空地, 1 表示障礙物 其中 a 和 b 也是在空地里面 改橘,求a(0滋尉,0) 到 b(3,2) 的最短距離 這里坐標為 (行飞主,列)
5行 4列
0 0 1 0
0 0 0 0
0 0 1 0
0 1 0 0
0 0 0 1
換句話說狮惜,廣度優(yōu)先搜索遍歷圖的過程是以a為起點,由近至遠既棺,依次訪問和va路徑相通且路徑長度為1,2...的頂點讽挟。
1、從 (0丸冕,0)開始搜索耽梅,以a點代替
a 0 1 0
0 0 0 0
0 0 1 0
0 1 0 0
0 0 0 1

-》
2、第二層搜索 從(0胖烛,0)搜索眼姐,右方和下方 以 b點 代替
a b 1 0
b 0 0 0
0 0 1 0
0 1 0 0
0 0 0 1

-》
3、第三層搜索 ,(0佩番,1)這個b點右邊是障礙物众旗,無法搜索,可以往下搜索(1趟畏,1)贡歧,(1,0)這個點搜索右方發(fā)現(xiàn)已經(jīng)搜索完成了(每個點需要搜索一次),跳過利朵,搜索(1律想,0)下方的點 (2,0)绍弟,以c代替
a b 1 0
b c 0 0
c 0 1 0
0 1 0 0
0 0 0 1

...
就這樣一直層層搜索直到搜索完成所有到點(3技即,2)的路線,結束搜索,遇到障礙物“1”跳過樟遣,最后變成下面這個地圖
a b 1 f
b c d e
c d 1 f
d 1 h g
e f g 1

完整demo如下

// 廣度優(yōu)化搜索
struct note
{
    int x; // 橫坐標
    int y; // 縱坐標
    int f; // 父親在隊列的的編號 而叼,需要輸出路徑才需要使用
    int s; // 步數(shù)
};
char* getDateTime(void);

int main(int argc, const char * argv[]) {
    struct note queB[2501]; // 因為地圖大小不會超過 50 * 50 所以 隊列擴展也不會超過2500個
    int aB[51][51], bookB[51][51];
    // 定義一個表示方向的數(shù)組
    int nextB [4][2] = {
        {0,1},      // 向右走
        {1,0},      // 向下走
        {0,-1},     // 向左走
        {-1,0}      // 向上走
    };
    int headB ,tailB;
    int iB,jB,kB,nB,mB,startX,startY,pB,qB,txB,tyB,flagB;
    
    printf("請輸入行和列:");
    scanf("%d %d",&nB,&mB);
    for (iB = 0; iB < nB; iB ++) {
        printf("輸入當前行地圖");
        for (jB = 0; jB < mB; jB++) {
            scanf("%d",&aB[iB][jB]);
        }
    }
    
    printf("輸入開始坐標startX,startY 結束坐標 pB qB");
    scanf("%d %d %d %d",&startX,&startY,&pB,&qB);
    
    // 隊列初始化
    headB = 0;
    tailB = 0;
    
    // 往隊列里面插入迷宮入口坐標
    queB[tailB].x = startX;
    queB[tailB].y = startY;
    queB[tailB].f = 0;
    queB[tailB].s = 0;
    tailB ++;
    bookB[startX][startY] = 1;
    
    
    flagB = 0;// 標記是否達到目標點豹悬,0表示沒有達到葵陵,1表示已經(jīng)達到了目標點
    // 當隊列部位空得時候循環(huán)
    while (headB < tailB) {
        
        // 枚舉4個方向
        for (kB = 0; kB< 4; kB ++) {
            
            // 計算下一個點的坐標
            txB = queB[headB].x + nextB[kB][0];
            tyB = queB[headB].y + nextB[kB][1];
            
            // 判斷是否越界
            if (txB < 0 || txB > nB || tyB < 0 || tyB > mB ) {
                continue;
            }
            
            // 判斷是否是障礙物,或者是已經(jīng)走過的路
            if (aB[txB][tyB] == 0 && bookB[txB][tyB] == 0) {
                // 不是障礙物瞻佛,并且沒有走過的路
                // 標記已經(jīng)走過的點埃难,廣度搜索和深度搜索不同,只需要走過一次不需要bookB數(shù)組還原
                bookB[txB][tyB] = 0;
                // 并且把這個點插入到隊列里面
                queB[tailB].x = txB;
                queB[tailB].y = tyB;
                queB[tailB].f = headB;  // 打印路徑需要涤久,因為點事從head里面擴展出來的
                queB[tailB].s = queB[headB].s + 1;// 步數(shù)是父親步數(shù)的 + 1
                tailB ++;
            }
            
            // 如果到達目標點涡尘,停止擴展,任務結束响迂,退出循環(huán)
            if (txB == pB && tyB == qB) {
                flagB = 1;
                break;
            }
        }
        
        if (flagB == 1) {
            break;
        }
        headB ++; // 當一個點擴展結束之后考抄,需要下一個點開始擴展
    }
    
    // 打印隊列中末尾最后的一個點的步數(shù)
    // 注意 tail 是指向隊尾 的下一個位置,這里需要減一
    //    for (iB = 0; iB < tailB; iB ++) {
    //        printf("%d ",queB[iB].f);
    //    }
    printf("\n最短的步數(shù)是:%d\n",queB[tailB - 1].s);
    getchar();
return;
}
char* getDateTime()
{
    static char nowtime[20];
    time_t rawtime;
    struct tm* ltime;
    time(&rawtime);
    ltime = localtime(&rawtime);
    strftime(nowtime, 20, "%Y-%m-%d %H:%M:%S", ltime);
    return nowtime;
}

本人也是剛剛學習蔗彤,如有錯誤川梅,請多多指正。
本文部分內(nèi)容參考 【啊哈然遏!算法】這本書
代碼例子

?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末贫途,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子待侵,更是在濱河造成了極大的恐慌丢早,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,941評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件秧倾,死亡現(xiàn)場離奇詭異怨酝,居然都是意外死亡,警方通過查閱死者的電腦和手機那先,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評論 3 395
  • 文/潘曉璐 我一進店門农猬,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人售淡,你說我怎么就攤上這事斤葱】犊澹” “怎么了?”我有些...
    開封第一講書人閱讀 165,345評論 0 356
  • 文/不壞的土叔 我叫張陵揍堕,是天一觀的道長换帜。 經(jīng)常有香客問我,道長鹤啡,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,851評論 1 295
  • 正文 為了忘掉前任蹲嚣,我火速辦了婚禮递瑰,結果婚禮上,老公的妹妹穿的比我還像新娘隙畜。我一直安慰自己抖部,他們只是感情好,可當我...
    茶點故事閱讀 67,868評論 6 392
  • 文/花漫 我一把揭開白布议惰。 她就那樣靜靜地躺著慎颗,像睡著了一般。 火紅的嫁衣襯著肌膚如雪言询。 梳的紋絲不亂的頭發(fā)上俯萎,一...
    開封第一講書人閱讀 51,688評論 1 305
  • 那天,我揣著相機與錄音运杭,去河邊找鬼夫啊。 笑死,一個胖子當著我的面吹牛辆憔,可吹牛的內(nèi)容都是我干的撇眯。 我是一名探鬼主播,決...
    沈念sama閱讀 40,414評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼虱咧,長吁一口氣:“原來是場噩夢啊……” “哼熊榛!你這毒婦竟也來了?” 一聲冷哼從身側響起腕巡,我...
    開封第一講書人閱讀 39,319評論 0 276
  • 序言:老撾萬榮一對情侶失蹤玄坦,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后绘沉,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體营搅,經(jīng)...
    沈念sama閱讀 45,775評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年梆砸,在試婚紗的時候發(fā)現(xiàn)自己被綠了转质。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,096評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡帖世,死狀恐怖休蟹,靈堂內(nèi)的尸體忽然破棺而出沸枯,到底是詐尸還是另有隱情,我是刑警寧澤赂弓,帶...
    沈念sama閱讀 35,789評論 5 346
  • 正文 年R本政府宣布绑榴,位于F島的核電站,受9級特大地震影響盈魁,放射性物質(zhì)發(fā)生泄漏翔怎。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,437評論 3 331
  • 文/蒙蒙 一杨耙、第九天 我趴在偏房一處隱蔽的房頂上張望赤套。 院中可真熱鬧,春花似錦珊膜、人聲如沸容握。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,993評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽剔氏。三九已至,卻和暖如春竹祷,著一層夾襖步出監(jiān)牢的瞬間谈跛,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,107評論 1 271
  • 我被黑心中介騙來泰國打工塑陵, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留币旧,地道東北人。 一個月前我還...
    沈念sama閱讀 48,308評論 3 372
  • 正文 我出身青樓猿妈,卻偏偏與公主長得像吹菱,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子彭则,可洞房花燭夜當晚...
    茶點故事閱讀 45,037評論 2 355

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

  • 一封紙質(zhì)書信鳍刷,娟秀的文字,左上角的幾朵梅花俯抖,無不透露著少女之情输瓜。或含蓄或溫婉芬萍,我們總愿把自己的赤誠之心尤揣,傾瀉在這一...
    官官小姐閱讀 309評論 0 2
  • 大家好北戏,我是“從容君“。 文 / 從容 寫在前面的話: 父母愛情漫蛔,原生態(tài)家庭的狀態(tài)嗜愈,直接影響著孩子成年后的情感婚姻...
    從容言閱讀 1,304評論 0 4
  • 很多妹子們到了冬天不愛穿羽絨服旧蛾,覺得穿起來臃腫,顯胖不好看……但不穿羽絨服怎么撐過零下的氣溫蠕嫁?今天就來扒一扒那些有...
    GreyStitchi灰針腳閱讀 19,290評論 0 2
  • 2017年6月24日 星期六 晴 【早起】05:00 【睡覺】21:30 【鍛煉】掄胳膊100個锨天,面壁蹲墻1...
    真泥閱讀 113評論 0 1
  • 你在遠方 兩千四百公里外的注視 你在北方 夏天也吹著難以站穩(wěn)的風 灼熱的空氣 扭曲的風景 刺眼的陽光 口中呼出的熱...
    棠莞爾閱讀 75評論 0 0