1. 程式人生 > >BFS解決八數碼問題和狼人過河問題

BFS解決八數碼問題和狼人過河問題

1、八數碼問題

問題描述:

初態:

0    1    2

3    4    5

6    7    8

如何移動交換0的位置達到終態

1    2     3

4    5     6

7    8     0

思路如下:

先將圖轉換為一個整數

初態: 876543210 終態: 087654321

構造狀態的資料結構

struct node{ int x; int where0; }

運動規則如下

switch where0: case0: d,r case1: d,l,r case2: d,l case3: u,d,r case4: u,d,l,r case5: u,d,l case6: u,r case7: u,l,r case8: u,l

switch dir: case u:t=x/10^(where0-3)%10; x=x-10^(where0-3)*t+10^where0*t; case d:t=x/10^(where0+3)%10; x=x-10^(where0+3)*t+10^where0*t; case l:t=x/10^(where0-1)%10; x=x-10^(where0-1)*t+10^where0*t; case r:t=x/10^(where0+1)%10; x=x-10^(where0+1)*t+10^where0*t;

程式碼:

#include<iostream>
#include<map>
#include<queue>
#include<cstdlib> 
using namespace std;

int pow10[10]={1,10,100,1000,10000,100000,
1000000,10000000,100000000,1000000000};

//資料結構 
struct node{
	int x;//表示當前狀態圖 
	int where0;//0的位置 
	struct node *pre;//父節點 
};

//運動規則 
node * goAction(node *p,int dir){
	int x=p->x,where0=p->where0;
	node *ans=(node *)malloc(sizeof(node));
	ans->pre=p;
	int t;
	switch(dir){
		case 1://up
			t=x/pow10[where0-3]%10;
			x=x-pow10[where0-3]*t+pow10[where0]*t;
			where0-=3;
			break;
		case 2://down
			t=x/pow10[where0+3]%10;   
			x=x-pow10[where0+3]*t+pow10[where0]*t;
			where0+=3;
			break;
		case 3://left
			t=x/pow10[where0-1]%10;   
			x=x-pow10[where0-1]*t+pow10[where0]*t;
			where0-=1;
			break;
		case 4://right
			t=x/pow10[where0+1]%10;   
			x=x-pow10[where0+1]*t+pow10[where0]*t;
			where0+=1;
			break;
	}
	ans->x=x;
	ans->where0=where0;
	return ans;	
}

queue<node *>nq;//狀態佇列 
map<int,int>nm;//判重 

//新節點加入佇列 
int join(node *a){
	if(nm[a->x]==1)//重複節點不加入佇列 
		return 0;
	if(a->x==87654321){//抵達終態 
		cout<<"路徑:"<<endl; 
		node *h=a;
		int step=0;
		while(h!=NULL)//列印路徑和步數 
		{
			cout<<h->x<<"  ";
			step++;
			h=h->pre;		
		}
		cout<<step<<endl;
		return 1;
	}
	nm[a->x]=1;
	nq.push(a);//加入佇列 
	return 0;
}

void fun(){
	
	while(!nq.empty()){
		node *p=nq.front();
		nq.pop();
		switch(p->where0){//運動規則 
			case 0:
				join(goAction(p,2));
				join(goAction(p,4));
				break;
			case 1:
				join(goAction(p,2));
				join(goAction(p,3));	
				join(goAction(p,4));
				break;
			case 2:
				join(goAction(p,2));
				join(goAction(p,3));
				break;
			case 3:
				join(goAction(p,1));
				join(goAction(p,2));
				join(goAction(p,4));
				break;
			case 4:
				join(goAction(p,1));
				join(goAction(p,2));
				join(goAction(p,3));
				join(goAction(p,4));
				break;
			case 5:
				join(goAction(p,1));
				join(goAction(p,2));
				join(goAction(p,3));
				break;
			case 6:
				join(goAction(p,1));
				join(goAction(p,4));
				break;
			case 7:
				join(goAction(p,1));
				join(goAction(p,3));
				join(goAction(p,4));
				break;
			case 8:
				join(goAction(p,1));
				join(goAction(p,3));
				break;

		}
			
	}
	 
}

int main()
{
	node *begin=(node *)malloc(sizeof(node));//初始狀態 
	begin->x=876543210;
	begin->where0=0;
	begin->pre=NULL;
	join(begin);
	fun();


}

2、狼人過河問題

問題描述:

{wolf,human,boat} 分別代表右岸的狼,人,船的數目

初態:{3,3,1} 終態:{0,0,0}

如何從初態抵達終態

規則: 1、每次過河船上可以一人或兩人 switch boat: case 0: boat++; wolf+=1||wolf+=2||human+=1||human+=2||wolf+=1,human+=1; case 1: boat--; wolf-=1||wolf-=2||human-=1||human-=2||wolf-=1,human-=1; 2、兩岸的狼不能比人多(人數不為0時) no1:wolf<0||wolf>3||human<0||human>3||boat<0||boat>1 no2:(human>0&&human<wolf)||((3-human)>0&&(3-human)<(3-wolf))

資料結構

struct node{ int wolf; int human; int boat; struct node *pre; };

程式碼:

#include<iostream>
#include<map>
#include<queue>
#include<cstdlib> 
#include<String>
using namespace std;

struct node{
int wolf;
int human;
int boat;
struct node *pre;
void init(int a,int b,int c,struct node *p){
	this->wolf=a;
	this->human=b;
	this->boat=c;
	this->pre=p;
}

bool operator < (const node x) const{//過載運算子,注意map是基於紅黑樹實現,每個節點需要具備可比性 
	int hash1=this->wolf*100+this->human*10+this->boat;
	int hash2=x.wolf*100+x.human*10+x.boat;
	return hash1<hash2;
}



};

queue<node *>nq;//狀態佇列 
map<node,int>nm;//狀態判重 

//判斷能否加入佇列 
int join(node *a){
	if(nm[*a]==1)
		return 0;
	int wolf=a->wolf,human=a->human,boat=a->boat;
	if(wolf<0||wolf>3||human<0||human>3||boat<0||boat>1)
		return 0;
	if((human>0&&human<wolf)||((3-human)>0&&(3-human)<(3-wolf)))
		return 0;
	if(a->wolf==0&&a->human==0&&a->boat==0){//終態 
		node *h=a;
		int step=0;
		while(h!=NULL){//列印路徑和步數 
			step++;
			cout<<"{ "<<h->wolf<<" , "<<h->human<<" , "<<h->boat<<" }  ";
			h=h->pre;
		}
		cout<<endl;
		cout<<step<<endl;
		return 1;
	}
	nm[*a]=1;
	nq.push(a);
	return 0;
}

//運動規則 
void goAction(node *p){
	node *a=(node *)malloc(sizeof(node));
	node *b=(node *)malloc(sizeof(node));
	node *c=(node *)malloc(sizeof(node));
	node *d=(node *)malloc(sizeof(node));
	node *e=(node *)malloc(sizeof(node));
	switch(p->boat){
		case 0://注意,不能在case裡新建變數 
			
			a->init(p->wolf+1,p->human,1,p);
			join(a);
			
			b->init(p->wolf+2,p->human,1,p);
			join(b);
			
			c->init(p->wolf,p->human+1,1,p);
			join(c);
			
			d->init(p->wolf,p->human+2,1,p);
			join(d);
			
			e->init(p->wolf+1,p->human+1,1,p);
			join(e);
			break;
		case 1:
			
			a->init(p->wolf-1,p->human,0,p);
			join(a);
			
			b->init(p->wolf-2,p->human,0,p);
			join(b);
			
			c->init(p->wolf,p->human-1,0,p);
			join(c);
			
			d->init(p->wolf,p->human-2,0,p);
			join(d);
			
			e->init(p->wolf-1,p->human+1,0,p);
			join(e);
			break;
	}
	return;
}



void fun(){
	while(!nq.empty()){
		node *p=nq.front();
		nq.pop();
		goAction(p);
	}
	
}

int main(){
	node *begin=(node *)malloc(sizeof(node));//初態 
	begin->init(3,3,1,NULL);
	join(begin);
	fun();

}