日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

[转载]双向广搜

發布時間:2025/4/9 编程问答 20 豆豆
生活随笔 收集整理的這篇文章主要介紹了 [转载]双向广搜 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
原文地址:雙向廣搜作者:qingge

?

?Eight???

?? 題目鏈接:http://acm.hdu.edu.cn/showproblem.php?pid=1043

?? 講到雙向廣搜,那就不能不講經典的八數碼問題,有人說不做此題人生不完整 。

?? 所謂雙向廣搜,就是初始結點向目標結點和目標結點向初始結點同時擴展,直至在兩個擴展方向上出現同一個結點,搜索結束。它適用的問題是,擴展結點較多,而目標結點又處在深沉,如果采用單純的廣搜解題,搜索量巨大,搜索速度慢是可想而知的,同時往往也會出現內存空間不夠用的情況,這時雙向廣搜的作用就體現出來了。雙向廣搜對單純的廣搜進行了改良或改造,加入了一定的“智能因數”,使搜索能盡快接近目標結點,減少了在空間和時間上的復雜度。

???當在講題前,不得不先給大家補充一點小知識,大家都知道搜索的題目其中難的一部分就是事物的狀態,不僅多而且復雜,要怎么保存每時刻的狀態,又容易進行狀態判重呢,這里提到了一種好辦法?? ------康托展開(只能針對部分問題)

?

康托展開

康托展開式:

? X=an*(n-1)!+an-1*(n-2)!+...+ai*(i-1)!+...+a2*1!+a1*0!

?其中,a為整數,并且0<=ai<i(1<=i<=n)。

?

例:

問:1324是{1,2,3,4}排列數中第幾個大的數?

解:第一位是1小于1的數沒有,是0個 0*3! 第二位是3小于3的數有1和2,但1已經在第一位了,所以只有一個數2 1*2! 。第三位是2小于2的數是1,但1在第一位,所以有0個數 0*1! ,所以比1324小的排列有0*3!+1*2!+0*1!=2個,1324是第三個大數。

?

好吧,先看下代碼實現:

int factory[]={1,1,2,6,24,120,720,5040,40320,362880}; // 0..n的階乘

?

int Gethash(char eight[])

{

?????? int k=0;

?????? for(int i=0;i<9;i++)??? // 因為它有八位數(針對八數碼問題)

?????? {

????????????? int t=0;

????????????? for(int j=i+1;j<9;j++)

???????????????????? if(eight[j]<eight[i])

??????????????????????????? t++;

????????????? k+=(t*factory[9-i-1]);

?????? }

?????? return k;?? // 返回該數是第幾大

}

好的,現在再來看看雙向廣搜模版:

void TBFS()

{

?????? bool found=false;

?????? memset(visited,0,sizeof(visited));? // 判重數組

?????? while(!Q1.empty())? Q1.pop();?? // 正向隊列

?????? while(!Q2.empty())? Q2.pop();? // 反向隊列

?????? //======正向擴展的狀態標記為1,反向擴展標記為2

?????? visited[s1.state]=1;?? // 初始狀態標記為1

?????? visited[s2.state]=2;?? // 結束狀態標記為2

?????? Q1.push(s1);? // 初始狀態入正向隊列

????? ?Q2.push(s2);? // 結束狀態入反向隊列

?????? while(!Q1.empty() || !Q2.empty())

?????? {

????????????? if(!Q1.empty())

???????????????????? BFS_expand(Q1,true);? // 在正向隊列中搜索

????????????? if(found)? // 搜索結束?

???????????????????? return ;

????????????? if(!Q2.empty())

???????????????????? BFS_expand(Q2,false);??// 在反向隊列中搜索

????????????? if(found) // 搜索結束

???????????????????? return ;

?????? }

}

void BFS_expand(queue<Status> &Q,bool flag)

{??

?????? s=Q.front();? // 從隊列中得到頭結點s

????? Q.pop()

????? for( 每個s 的子節點 t )

???? {

?????????????t.state=Gethash(t.temp)? // 獲取子節點的狀態

????????? ???if(flag)?? // 在正向隊列中判斷

???????????? {

????????????????????? if (visited[t.state]!=1)// 沒在正向隊列出現過

??????????????????? {

?????????????????????????? if(visited[t.state]==2)? // 該狀態在反向隊列中出現過

?????? ?????????????????? {

?????????????????????????????????各種操作;

?????????????????????????????? ??found=true;

?????????????????????????????????return;

???????????????????????????}

??????????????????????????? visited[t.state]=1;?? // 標記為在在正向隊列中

??????????????????????????? Q.push(t);? // 入隊

?????????????????????? }

???????????? }

???????????? else??? // 在正向隊列中判斷

???????????? {

????????????????????? if (visited[t.state]!=2) // 沒在反向隊列出現過

??????????????????? {

?????????????????????????? if(visited[t.state]==1)? // 該狀態在正向向隊列中出現過

?????? ??????????????????? {

????????????????????????????????? 各種操作;

????????????????????????????????? found=true;

???????????????????????? ?????????return;

????????????????????????????}

???????????????????????????? visited[t.state]=2;??// 標記為在反向隊列中

?????????????????????????????Q.push(t);? // 入隊

?????????????????????? }

???????????? }?????????????

}? ???????????????????

?

好的,現在開始說說八數碼問題

其實,Eight有一個很重要的判斷,那就是逆序數的判斷。如果i>j,并且ai<aj,那么定義(i,j)為一個逆序對,而對于一個狀態排列中所含的逆序對的個數總和就是逆序數。而本題的逆序數的奇偶性的判斷是至關重要的:

如果x在同一行上面移動那么1~8的逆序數不變

如果x在同一列上面移動,每次逆序數增加偶數個或者減少偶數個

因為目標結點的狀態的逆序數為0,為偶數,所以每次訪問到的狀態的逆序數也必須為偶數,保持奇偶性性質,否則就不必保存該狀態。

?

#include<iostream>

#include<queue>

using namespace std;

?

#define N 10

#define MAX 365000

?

char visited[MAX];

int father1[MAX];? // 保存正向搜索當前狀態的父親狀態結點

int father2[MAX];? // 保存反向搜索當前狀態的父親狀態結點

int move1[MAX];??? // 正向搜索的方向保存

int move2[MAX];?? //? 反向搜索的方向保存

?

struct Status?? // 結構

{

?????? char eight[N];? // 八數碼狀態

?????? int space;???? // x 位置

?????? int state;??? // hash值,用于狀態保存與判重?

};

?

queue<Status> Q1;? // 正向隊列

queue<Status> Q2;? // 反向隊列

?

Status s,s1,s2,t;

?

bool found;? // 搜索成功標記

?

int state;?? // 正反搜索的相交狀態

?

int factory[]={1,1,2,6,24,120,720,5040,40320,362880};? // 0..n的階乘

?

int dir[4][2]={{-1,0},{1,0},{0,-1},{0,1}};

?

int Gethash(char eight[])? // 康托展開(獲取狀態,用于判重)

{

?????? int k=0;

?????? for(int i=0;i<9;i++)

?????? {

????????????? int t=0;

????????????? for(int j=i+1;j<9;j++)

???????????????????? if(eight[j]<eight[i])

??????????????????????????? t++;

????????????? k+=(t*factory[9-i-1]);

?????? }

?????? return k;

}

?

int ReverseOrder(char eight[])? // 求狀態的逆序數

{

?????? int i,j,num=0;

?????? for(i=0;i<9;i++)

?????? {

????????????? for(j=0;j<i;j++)

????????????? {

???????????????????? if(int(eight[i])==9)

???????????????????? {

??????????????????????????? break;

???????????????????? }

???????????????????? if(int(eight[j])==9)

??????????????????????????? continue;

???????????????????? if(int(eight[j])>int(eight[i]))

??????????????????????????? num++;

????????????? }

?????? }

?????? num=num%2;

?????? return num;

}

?

void BFS_expand(queue<Status> &Q,bool flag)? // 單向廣度搜索

{

?????? int k,x,y;

?????? s=Q.front();

?????? Q.pop();

?????? k=s.space;

?????? x=k/3;

?????? y=k%3;

?????? for(int i=0;i<4;i++)

?????? {

????????????? int xx=x+dir[i][0];

????????????? int yy=y+dir[i][1];

????????????? if(xx>=0 && xx<=2 && yy>=0 && yy<=2)

????????????? {

???????????????????? t=s;

???????????????????? t.space=xx*3+yy;?? // 計算x位置

???????????????????? swap(t.eight[k],t.eight[t.space]);? // 交換兩個數位置

???????????????????? t.state=Gethash(t.eight);

???????????????????? if(flag)? // 在正向隊列中判斷

???????????????????? {

??????????????????????????? if(visited[t.state]!=1 && ReverseOrder(t.eight)==0)? // 未在正向隊列出現過并且滿足奇偶性

??????????????????????????? {

?????????????????????????????????? move1[t.state]=i;? // 保存正向搜索的方向

?????????????????????????????????? father1[t.state]=s.state;?// 保存正向搜索當前狀態的父親狀態結點

?????????????????????????????????? if(visited[t.state]==2)?? //? 當前狀態在反向隊列中出現過

?????????????????????????????????? {

????????????????????????????????????????? state=t.state;? // 保存正反搜索中相撞的狀態(及相交點)

??????????????????????????? ????????????? found=true;??? // 搜索成功

????????????????????????????????????????? return;

?????????????????????????????????? }

?????????????????????????????????? visited[t.state]=1;?? // 標記為在正向隊列中

?????????????????????????????????? Q.push(t);? // 入隊

??????????????????????????? }

???????????????????? }

???????????????????? else? // 在反向隊列中判斷

???????????????????? {

??????????????????????????? if(visited[t.state]!=2 && ReverseOrder(t.eight)==0)???// 未在反向隊列出現過并且滿足奇偶性

??????????????????????????? {

?????????????????????????????????? move2[t.state]=i;? // 保存反向搜索的方向

?????????????????????????????????? father2[t.state]=s.state;?// 保存反向搜索當前狀態的父親狀態結點

?????????????????????????????????? if(visited[t.state]==1)? //? 當前狀態在正向隊列中出現過

?????????????????????????????????? {

????????????????????????????????????????? state=t.state;? // 保存正反搜索中相撞的狀態(及相交點)

????????????????????????????????????????? found=true;?? // 搜索成功

????????????????????????????????????????? return;

?????????????????????????????????? }

?????????????????????????????????? visited[t.state]=2;? // 標記為在反向隊列中

?????????????????????????????????? Q.push(t);?? // 入隊

??????????????????????????? }

???????????????????? }

????????????? }

?????? }

?????? return ;

}

?

void TBFS()??????????? // 雙向搜索

{

?????? memset(visited,0,sizeof(visited));

?????? while(!Q1.empty())

????????????? Q1.pop();

?????? while(!Q2.empty())

????????????? Q2.pop();

?????? visited[s1.state]=1;?? // 初始狀態

?????? father1[s1.state]=-1;

?????? visited[s2.state]=2;?? // 目標狀態

?????? father2[s2.state]=-1;

?????? Q1.push(s1);

?????? Q2.push(s2);

?????? while(!Q1.empty() || !Q2.empty())

?????? {

????????????? if(!Q1.empty())

???????????????????? BFS_expand(Q1,true);

????????????? if(found)

???????????????????? return ;

????????????? if(!Q2.empty())

???????????????????? BFS_expand(Q2,false);

????????????? if(found)

???????????????????? return ;

?????? }

}

?

void PrintPath1(int father[],int move[])?? // 從相交狀態向初始狀態尋找路徑

{

?????? int n,u;

?????? char path[1000];

?????? n=1;

?????? path[0]=move[state];

?????? u=father[state];

?????? while(father[u]!=-1)

?????? {

????????????? path[n]=move[u];

????????????? n++;

????????????? u=father[u];

?????? }

?????? for(int i=n-1;i>=0;--i)

?????? {???????

????????????? if(path[i] == 0)???????????

???????????????????? printf("u");???????

????????????? else if(path[i] == 1)???????????

???????????????????? printf("d");???????

????????????? else if(path[i] == 2)???????????

???????????????????? printf("l");???????

????????????? else???????????

???????????????????? printf("r");???

?????? }

}

?

void PrintPath2(int father[],int move[])?? // 從相交狀態向目標狀態尋找路徑

{

?????? int n,u;

?????? char path[1000];

?????? n=1;

?????? path[0]=move[state];

?????? u=father[state];

?????? while(father[u]!=-1)

?????? {

????????????? path[n]=move[u];

????????????? n++;

????????????? u=father[u];

?????? }

?????? for(int i=0;i<=n-1;i++)

?????? {???????

????????????? if(path[i] == 0)???????????

???????????????????? printf("d");???????

????????????? else if(path[i] == 1)???????????

???????????????????? printf("u");???????

????????????? else if(path[i] == 2)???????????

???????????????????? printf("r");???????

????????????? else???????????

???????????????????? printf("l");???

?????? }

}

?

int main()

{

?????? int i;

?????? char c;???

?????? while(scanf(" %c",&c)!=EOF)

?????? {

????????????? if(c=='x')

????????????? {

???????????????????? s1.eight[0]=9;

???????????????????? s1.space=0;

????????????? }

????????????? else

???????????????????? s1.eight[0]=c-'0';

????????????? for(i=1;i<9;i++)

????????????? {

???????????????????? scanf(" %c",&c);

???????????????????? if(c=='x')

???????????????????? {

??????????????????????????? s1.eight[i]=9;

??????????????????????????? s1.space=i;

???????????????????? }

???????????????????? else

??????????????????????????? s1.eight[i]=c-'0';

????????????? }

????????????? s1.state=Gethash(s1.eight);

????????????? for(int i=0;i<9;i++)

???????????????????? s2.eight[i]=i+1;

????????????? s2.space=8;

????????????? s2.state=Gethash(s2.eight);

????????????? if(ReverseOrder(s1.eight)==1)

????????????? {

???????????????????? cout<<"unsolvable"<<endl;

???????????????????? continue;

????????????? }

????????????? found=false;

????????????? TBFS();

????????????? if(found)?? // 搜索成功

????????????? {

???????????????????? PrintPath1(father1,move1);

???????????????????? PrintPath2(father2,move2);

????????????? }

????????????? else

???????????????????? cout<<"unsolvable"<<endl;

????????????? cout<<endl;

?????? }

?????? return 0;

}

轉載于:https://www.cnblogs.com/csgc0131123/p/5290397.html

總結

以上是生活随笔為你收集整理的[转载]双向广搜的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。