日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 >

算法笔记之回溯法(2)

發(fā)布時(shí)間:2025/3/21 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 算法笔记之回溯法(2) 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

著色問題

問題分析

假設(shè)地圖共有7個(gè)區(qū)域,分別是A/B/C/D/E/F/G,對(duì)上面順序進(jìn)行編號(hào),每個(gè)區(qū)域用一個(gè)結(jié)點(diǎn)表示,相鄰的區(qū)域有連線,那么地圖就轉(zhuǎn)化成一個(gè)無向連接圖。

算法設(shè)計(jì)

  • 定義問題的解空間。圖的m著色問題解空間形式為n元組{x1,x2,...,xi,...,xn},每個(gè)分量取值為1,2,3,...,m,即問題的解是一個(gè)n元向量。由此可得,問題的解空間為{x1,x2,...,xi,...,xn},其中顯約束為xi=1,2,...,m。
  • 確定解空間的組織結(jié)構(gòu):一顆滿m叉樹,樹的深度為n。
  • 搜索解空間

    • 約束條件:假設(shè)當(dāng)前擴(kuò)展結(jié)點(diǎn)位于解空間樹的第t層,那么從第1到第t-1層的結(jié)點(diǎn)情況都已經(jīng)確定,接下來是按照擴(kuò)展結(jié)點(diǎn)的第一個(gè)分支進(jìn)行擴(kuò)展,此時(shí)需要判斷是否將第t個(gè)結(jié)點(diǎn)著色情況。第t個(gè)結(jié)點(diǎn)的色號(hào)要與前t-1個(gè)結(jié)點(diǎn)中與其有邊相連的結(jié)點(diǎn)顏色不同,如果有顏色相同的,則第t個(gè)結(jié)點(diǎn)不能用這個(gè)色號(hào),換下一個(gè)色號(hào)嘗試。
    • 限界條件:無。
    • 搜索過程:擴(kuò)展結(jié)點(diǎn)沿著第一個(gè)分支擴(kuò)展,判斷約束條件,滿足則進(jìn)入深一層繼續(xù)搜索;如果不滿足,則擴(kuò)展生成的結(jié)點(diǎn)被剪掉,換下一個(gè)色號(hào)嘗試。如果所有色號(hào)都嘗試完畢,該結(jié)點(diǎn)變成死結(jié)點(diǎn),向上回溯到距離其最近的活結(jié)點(diǎn),繼續(xù)搜索。搜索到葉子結(jié)點(diǎn)時(shí),找到一種著色方案,搜索過程直到全部活結(jié)點(diǎn)變成死結(jié)點(diǎn)為止。
  • 解題過程

    地圖7個(gè)區(qū)域,3種顏色。

  • 開始搜索第1層(t=1)。擴(kuò)展A結(jié)點(diǎn)第一個(gè)分支,首先判斷是否滿足約束條件,因?yàn)橹斑€未著色任何結(jié)點(diǎn),所以滿足約束條件,擴(kuò)展該分支,令1號(hào)結(jié)點(diǎn)著1號(hào)色,即x[1]=1,生成B。
  • 拓展B結(jié)點(diǎn)(t=2)。擴(kuò)展第一個(gè)分支x[2]=1,首先判斷2號(hào)結(jié)點(diǎn)是否和前面已經(jīng)確定色號(hào)的結(jié)點(diǎn)(1號(hào))有邊相連且色號(hào)相同,不滿足約束條件,剪掉該分支,然后沿著x[2]=2擴(kuò)展,2號(hào)結(jié)點(diǎn)和前面已經(jīng)確定色號(hào)的結(jié)點(diǎn)(1號(hào))有邊相連,但色號(hào)不同,滿足約束條件,擴(kuò)展該分支,令x[2]=2。
  • 擴(kuò)展C結(jié)點(diǎn)(t=3)。擴(kuò)展第一個(gè)分支x[3]=1,首先判斷3號(hào)結(jié)點(diǎn)是否和前面已經(jīng)確定色號(hào)的結(jié)點(diǎn)(1、2號(hào))有邊相連且色號(hào)相同,不滿足約束條件,剪掉該分支;同理剪掉x[3]=2分支。然后沿著x[3]=3擴(kuò)展,3號(hào)結(jié)點(diǎn)和前面已經(jīng)確定色號(hào)的結(jié)點(diǎn)(1、2號(hào))有邊相連,但色號(hào)不同,滿足約束條件,擴(kuò)展該分支,令x[3]=3。生成D。
  • 擴(kuò)展D結(jié)點(diǎn)(t=4)。擴(kuò)展第一個(gè)分支x[4]=1,首先判斷4號(hào)結(jié)點(diǎn)是否和前面已經(jīng)確定色號(hào)的結(jié)點(diǎn)(1、2、3號(hào))有邊相連且色號(hào)相同,不滿足約束條件(4余1相連),剪掉該分支;然后令x[4]=2,符合條件,生成E。
  • 擴(kuò)展E結(jié)點(diǎn)(t=5)。擴(kuò)展第一個(gè)分支x[5]=1,首先判斷4號(hào)結(jié)點(diǎn)是否和前面已經(jīng)確定色號(hào)的結(jié)點(diǎn)(1、2、3號(hào))有邊相連且色號(hào)相同,確定5與2、3、4相連但色號(hào)不同,滿足約束條件,擴(kuò)展該分支,生成F。
  • 擴(kuò)展F結(jié)點(diǎn)(t=6)。擴(kuò)展第一個(gè)分支x[6]=1,同理不滿足,剪掉分支;然后沿著x[6]=2擴(kuò)展,6與5號(hào)有邊相連但色號(hào)不同,故滿足約束條件,擴(kuò)展該分支,令x[6]=2,生成G。
  • 擴(kuò)展G結(jié)點(diǎn)(t=7)。擴(kuò)展第一個(gè)分支x[7]=1,剪掉x[7]=1和x[7]=2的分支,然后令x[7]=3,符合要求,生成H。
  • 擴(kuò)展H結(jié)點(diǎn)(t=8)。t>n,找到一個(gè)可行解,輸出該可行解{1,2,3,2,1,2,3},回溯到最近的活結(jié)點(diǎn)G。
  • 重新擴(kuò)展G結(jié)點(diǎn)(t=7)。G已經(jīng)考察完畢,成為死結(jié)點(diǎn),回溯到最近的活結(jié)點(diǎn)F。
  • 繼續(xù)搜索,又找到第二種著色方案,輸出可行解{1,3,2,3,1,3,2}。
  • 繼續(xù)搜索,又找到4個(gè)可行解。
  • 代碼實(shí)現(xiàn)

    //約束條件 bool isRight(int t) {for (int j = 1; j < t; j++){if (map[t][j]){if (x[j] == x[t])return false;}}return true; }//回溯方法函數(shù) void Backtrack(int t) {if (t > n){sum++;cout << "第" << sum << "種方案:";for (int i = 1; i <= n; i++)//輸出該著色方案{cout << x[i] << " ";}cout << endl;}else {for (int i = 1; i <= m; i++){x[t] = i;if (isRight(t))Backtrack(t + 1);}} }

    算法復(fù)雜度分析

  • 時(shí)間復(fù)雜度:O(nmn)。
  • 空間復(fù)雜度:O(n)。
  • n皇后問題

    問題介紹

    在n×n的棋盤上放置彼此不受攻擊的n個(gè)皇后。按照國(guó)際象棋規(guī)則,皇后可以攻擊與之在同一行、同一列、同一斜線上的棋子。現(xiàn)在在n*n的棋盤上放置n個(gè)皇后,使其不受攻擊。

    問題分析

    求解策略:
    以行為主導(dǎo):

    • 在第1行第1列放置第一個(gè)皇后。
    • 在第2行放置第2個(gè)皇后。第2個(gè)皇后的位置不能和前面的皇后同列、同斜線,不用再判斷同行了,因?yàn)槊啃形覀儽緛砭椭环乓粋€(gè)。
    • 在第3行放置第3個(gè)皇后。第3個(gè)皇后的位置不能和前面的皇后同列、同斜線。
    • ……
    • 在第t行放置第t個(gè)皇后。第t個(gè)皇后的位置不能和前面的皇后同列、同斜線。
    • ……
    • 在第n行放置第n個(gè)皇后。第n個(gè)皇后的位置不能和前面的皇后同列、同斜線。

    算法設(shè)計(jì)

    (1)定義問題的解空間。n皇后問題解的形式為n元組:{x1,x2,...,xi,...,xn},分量xi表示第i個(gè)皇后放置在第i行第xi列,xi取值為1,2,3,...,n。顯約束為不同行。

    (2)解空間的組織結(jié)構(gòu):一顆m(m=n)叉樹,樹深度為n。

    (3)搜索解空間。
    約束條件:在第t行放置第t個(gè)皇后時(shí),第t個(gè)皇后的位置不能和前t-1個(gè)皇后同列、同斜線。第i個(gè)皇后和第j個(gè)皇后不同列,即xi!=xj

    限界條件:不需要設(shè)置。

    搜索過程:

    從根開始,以DFS的方式進(jìn)行搜索。根節(jié)點(diǎn)是活結(jié)點(diǎn),并且是當(dāng)前的擴(kuò)展結(jié)點(diǎn)。在搜索過程中,當(dāng)前的擴(kuò)展結(jié)點(diǎn)沿縱深方向移向一個(gè)新結(jié)點(diǎn),判斷該新結(jié)點(diǎn)是否滿足隱約束。如果滿足,則該新結(jié)點(diǎn)成為活結(jié)點(diǎn),并且成為當(dāng)前的擴(kuò)展結(jié)點(diǎn),繼續(xù)深一層的搜索;如果不滿足,則換到該新結(jié)點(diǎn)的兄弟結(jié)點(diǎn)繼續(xù)搜索;如果新結(jié)點(diǎn)沒有兄弟結(jié)點(diǎn),或其兄弟結(jié)點(diǎn)已全部搜索完畢,則擴(kuò)展結(jié)點(diǎn)成為死結(jié)點(diǎn),搜索回溯到其父結(jié)點(diǎn)處繼續(xù)進(jìn)行。搜索過程直到找到問題的根結(jié)點(diǎn)變成死結(jié)點(diǎn)為止。

    代碼實(shí)現(xiàn)

    bool isPlace(int t) {bool place = true;for (int j = 1; j < t; j++){if (x[t] == x[j] || t - j == fabs(x[t] - x[j]))//判斷列、對(duì)角線是否沖突{place = false;break;}}return place; }void backtrack(int t) {if (t > n){countn++;for (int i = 1; i <= n; i++){cout << x[i] << " ";}cout << endl;cout << "---------" << endl;}else{//分別判斷n個(gè)分支,特別注意i不要定義為全局變量,否則遞歸調(diào)用有問題for (int i = 1; i <= n; i++){x[t] = i;if (isPlace(t))backtrack(t + 1);//上面說的是不沖突就進(jìn)行下一行搜索}} }

    算法復(fù)雜度分析

  • 時(shí)間復(fù)雜度:O(nn+1)。
  • 空間復(fù)雜度:O(n)。
  • 最優(yōu)加工順序

    問題描述

    現(xiàn)在有3個(gè)機(jī)器零件{J1,J2,J3},在第一臺(tái)機(jī)器上的加工時(shí)間分別為2、5、4,在第二臺(tái)機(jī)器上的加工時(shí)間分別為3、1、6.如何安排零件加工順序,使第一個(gè)零件從機(jī)器1上加工開始到最后一個(gè)零件在機(jī)器2上加工完成,所需的總加工時(shí)間最短?

    問題分析

    我們通過分析可以發(fā)現(xiàn),第一臺(tái)機(jī)器可以連續(xù)加工,而第二臺(tái)機(jī)器開始加工的時(shí)間是當(dāng)前第一臺(tái)機(jī)器的下線時(shí)間第二臺(tái)機(jī)器下線時(shí)間最大值
    實(shí)際上就是找到n個(gè)機(jī)器零件的一個(gè)排列,使總的加工時(shí)間最短。

    算法設(shè)計(jì)

  • 定義問題的解空間。解的形式為n元組:{x1,x2,...,xi,...,xn},分量xi表示第i個(gè)加工的零件號(hào),n個(gè)零件組成的集合為S={1,2,...,n},xi取值為S-{x1,x2,...,xi-1}。
  • 解空間的組織形式為一顆排列數(shù),深度為n。
  • 搜索解空間。

    • 約束條件:無約束條件。
    • 限界條件:用f2表示當(dāng)前已完成的零件在第二臺(tái)機(jī)器加工結(jié)束所用的時(shí)間,用bestf表示當(dāng)前找到的最優(yōu)加工方案的完成時(shí)間。顯然,繼續(xù)向深處搜索時(shí),f2不會(huì)減少,只會(huì)增加。因此,當(dāng)f2≥bestf時(shí),沒有繼續(xù)向深處搜索的必要。限界條件可以描述為:f2。f2初值為0,bestf的初值為無窮大。
  • 搜索過程。擴(kuò)展結(jié)點(diǎn)沿著某個(gè)分支擴(kuò)展時(shí)需要判斷限界條件,如果滿足,則進(jìn)入深一層繼續(xù)搜索;如果不滿足,則剪掉該分支。搜索到葉子結(jié)點(diǎn)的時(shí)候,即找到當(dāng)前最優(yōu)解。搜索直到全部活結(jié)變成死結(jié)點(diǎn)為止。
  • 代碼實(shí)現(xiàn)

    1.數(shù)據(jù)結(jié)構(gòu)

    struct node {//機(jī)器零件在第一臺(tái)機(jī)器上的加工時(shí)間x和第二胎機(jī)器上的加工時(shí)間yint x,y; }T[MAX];

    2.按限界條件進(jìn)行搜索求解:t表示當(dāng)前擴(kuò)展結(jié)點(diǎn)在第t層,f1表示當(dāng)前第一臺(tái)機(jī)器上加工的完成時(shí)間,f2表示當(dāng)前第二臺(tái)機(jī)器上加工的完成時(shí)間。如果t>n表示已經(jīng)到達(dá)葉子結(jié)點(diǎn),記錄最優(yōu)值和最優(yōu)解,返回。否則,分別判斷每個(gè)分支是否滿足約束條件,若滿足則進(jìn)入下一層backtrack(t+1);如果不滿足則反操作復(fù)位,考察下一個(gè)分支(兄弟結(jié)點(diǎn))。

    void Backtrack(int t) {if(t>n){for(int i=1;i<=n;i++)bestx[i]=x[i];//記錄最優(yōu)隊(duì)列bestf=f2;//更新最優(yōu)值return ;}for(int i=t;i<=n;i++){f1+=T[x[i].x;int temp=f2;f2=max(f1,f2)+T[x[i]].y;if(f2<bestf)//滿足限界條件{swap(x[t],x[i]);//交換Backtrack(t+1);//繼續(xù)搜索swap(x[t],x[i]);//復(fù)位,反操作}f1-=T[x[i]].x;//復(fù)位,反操作f2=temp;//復(fù)位,反操作} }

    算法復(fù)雜度分析

    時(shí)間復(fù)雜度為O(nn!)≈O((n+1)!),空間復(fù)雜度為O(n)。

    算法優(yōu)化改進(jìn)

    新的算法的時(shí)間復(fù)雜度為O(nlogn),空間復(fù)雜度為O(n)。利用貝爾曼規(guī)則,代碼如下:

    #include<iostream> #include<algorithm> using namespace std ; const int MX=10000+5 ; int n; struct node {int id;int x,y; }T[MX] ; bool cmp(node a,node b) {return min(b.x,a.y)>=min(b.y,a.x);//按照貝爾曼規(guī)則排序 } int main() {cout<<"請(qǐng)輸入機(jī)器零件的個(gè)數(shù) n:";cin>>n;cout<<"請(qǐng)依次輸入每個(gè)機(jī)器零件在第一臺(tái)機(jī)器上的加工時(shí)間x和第二臺(tái)機(jī)器上的加工時(shí)間y:";for(int i=0;i<n;i++){cin>>T[i].x>>T[i].y;T[i].id=i+1;}sort(T,T+n,cmp); //排序int f1=0,f2=0;for(int i=0;i<n;i++) //計(jì)算總時(shí)間{f1+=T[i].x;f2=max(f1,f2)+T[i].y;}cout<<"最優(yōu)的機(jī)器零件加工順序?yàn)?";for(int i=0;i<n;i++) //輸出最優(yōu)加工順序cout<<T[i].id<<" ";cout<<endl;cout<<"最優(yōu)的機(jī)器零件加工的時(shí)間為:";cout<<f2<<endl;return 0 ; }

    總結(jié)

    以上是生活随笔為你收集整理的算法笔记之回溯法(2)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。