1. 程式人生 > >修道士與野人問題(BFS廣度搜索)

修道士與野人問題(BFS廣度搜索)

all 插入 stat for ont ios tar span start

#include  "iostream.h"
#include "string.h"
//定義一個狀態節點
typedef struct //存儲各個狀態
{
    int       x,y,s;//修道士人數,野人人數,s=0左岸s=1右岸
}state;

typedef struct edge
{
   int verNo;//頂點號;
   int x_boat,y_boat,di;//船上修道士人數,船上野人人數,方向,di=1向右,di=0向左
   struct edge* next;
}edge;

typedef struct
{
   state st;
   edge *e;
}vert;

typedef 
struct { vert ver[1000] ; int vNum; }adjGraph; typedef struct { int pos;//pos為該狀態在鄰接表的頂點表中的位置 int pre;//pre指的是隊中當前元素前驅在qu.dt中的位置 }data; typedef struct { data dt[1000]; int front,rear; }Queue; //創建頂點表,並記錄所有狀態的個數adj.vNum void CreteAllState(adjGraph &adj,int m,int n) { for (int
c1=0;c1<=1;c1++) for(int m1=0;m1<=m;m1++) for (int n1=0;n1<=n&&n1<=m1||m1==0&&n1<=n;n1++)//野人要少於修道士人數或全是野人 { adj.ver[adj.vNum].st.s=c1; adj.ver[adj.vNum].st.x=m1; adj.ver[adj.vNum].st.y=n1; adj.ver[adj.vNum].e
=NULL; cout<<c1<<\t<<m1<<\t<<n1<<\t<<adj.vNum<<endl; adj.vNum++; } } //在頂點表中查找狀態位置(下標) int SearchState(adjGraph adj,state st) { for (int i=0;i<adj.vNum;i++) if(st.s==adj.ver[i].st.s && st.x==adj.ver[i].st.x && st.y==adj.ver[i].st.y) return i; return -1; } int CheckState(adjGraph adj,state st,int m,int n)//判斷st狀態是否可作為第i狀態的後續狀態,如果是則返回後續狀態的位置,否則返回-1; { int pos;state st_OtherSide; st_OtherSide.s=st.s==1?0:1; st_OtherSide.x=m-st.x; st_OtherSide.y=n-st.y; pos=SearchState(adj,st_OtherSide); if(pos==-1) return -1; pos=SearchState(adj,st); if(pos==-1) return -1; return pos; } //創建邊表 void CreateEdges(adjGraph &adj,int m,int n,int c) { edge *t;state st;int j,k,vNo; for(int i=0;i<adj.vNum;i++) { if (adj.ver[i].st.x+adj.ver[i].st.y>0)//修道士與野人總數大於0 { if(adj.ver[i].st.y>0)//假如船上全部為野人 for (j=1;j<=adj.ver[i].st.y&&j<=c;j++) { st.s=adj.ver[i].st.s==1?0:1; st.x=m-adj.ver[i].st.x; st.y=n-(adj.ver[i].st.y-j); vNo=CheckState(adj,st,m,n); if(vNo==-1) continue; //非法狀態則跳過 t=new edge;//左岸就往右岸的狀態轉變 t->verNo=vNo;t->di=st.s;t->x_boat=0;t->y_boat=j; t->next=adj.ver[i].e;//頭插法 adj.ver[i].e=t; } if(adj.ver[i].st.x>1)//船上有j個修道士與k個野人 for (j=1;j<=adj.ver[i].st.x&&j<=c;j++)// for (k=0;k<=c-j&&k<=adj.ver[i].st.y;k++) { st.s=adj.ver[i].st.s==1?0:1; st.x=m-(adj.ver[i].st.x-j); st.y=n-(adj.ver[i].st.y-k); vNo=CheckState(adj,st,m,n); if(vNo==-1) continue;//非法狀態則跳過 t=new edge;//右岸就往左岸的狀態轉變 t->verNo=vNo;t->di=st.s;t->x_boat=j;t->y_boat=k; t->next=adj.ver[i].e;//頭插法 adj.ver[i].e=t; } } } } void Disp(adjGraph adj) { edge *e; for (int i=0;i<adj.vNum;i++) { cout<<i<<\t; cout<<adj.ver[i].st.s<<\t; cout<<adj.ver[i].st.x<<\t; cout<<adj.ver[i].st.y<<\t; e=adj.ver[i].e; cout<<endl; while (e) { cout<<\t<<"頂點號"<<\t<<"方向"<<\t<<"船上修道士"<<\t<<"船上野人"<<endl; cout<<\t<<e->verNo<<\t<<e->di<<\t<<e->x_boat<<\t<<e->y_boat<<endl; e=e->next; } cout<<endl; } } void PrintPath1(adjGraph &adj,Queue &qu,int i)//由i向前找路 { if (qu.dt[i].pre!=-1) PrintPath1(adj,qu,qu.dt[i].pre); int k=qu.dt[i].pos; cout<<i<<\t; cout<<adj.ver[k].st.s<<\t; cout<<adj.ver[k].st.x<<\t; cout<<adj.ver[k].st.y<<\t; cout<<endl; } void PrintPath(adjGraph &adj,Queue &qu,int i)//由i向前找路 { for (int k=0;k<=i;k++) { cout<<k<<\t; cout<<qu.dt[k].pos<<\t; cout<<qu.dt[k].pre<<\t; cout<<endl; } } void BreadthSearch(adjGraph adj,int* visit,Queue &qu,int x,int y) { int stPos,finPos,tag=1; qu.front=qu.rear=-1; state st,fin; st.s=0;st.x=x;st.y=y; stPos=CheckState(adj,st,x,y); if(stPos==-1) cout<<"start position error!"<<endl; fin.s=1;fin.x=x;fin.y=y; finPos=SearchState(adj,fin); qu.rear++; qu.dt[qu.rear].pos=stPos;//起始位置入隊 qu.dt[qu.rear].pre=-1;//pre指的是隊中當前元素前驅在qu.dt中的位置 while(qu.rear!=qu.front&&tag) { qu.front++;//出隊一元素 visit[qu.dt[qu.front].pos]=1; if (qu.dt[qu.front].pos==finPos) { tag=0; cout<<"find the path!"<<endl; PrintPath1(adj,qu,qu.front); //插入打印路徑的函數 break; } edge *e; e=adj.ver[qu.dt[qu.front].pos].e;//e points to the first adjacent edge; while (e) { if(visit[e->verNo]==0) { qu.dt[++qu.rear].pos=e->verNo; qu.dt[qu.rear].pre=qu.front; } e=e->next; } } if(tag==1) cout<<"cant find the path!"<<endl; } void main() { int m,n,c;//修道士人數,野人人數,船上最多可載人數 adjGraph adj;Queue qu; adj.vNum=0; cin>>m>>n>>c; CreteAllState(adj,m,n); CreateEdges(adj,m,n,c); Disp(adj); int visit[1000]; memset(visit,0,sizeof(visit));//把數組置空 BreadthSearch(adj,visit,qu,m,n); }

去掉調試代碼:

#include  "iostream.h"
#include "string.h"
//定義一個狀態節點
typedef struct //存儲各個狀態
{
	int       x,y,s;//修道士人數,野人人數,s=0左岸s=1右岸
}state;

typedef struct edge
{
   int verNo;//頂點號;
   int x_boat,y_boat,di;//船上修道士人數,船上野人人數,方向,di=1向右,di=0向左
   struct edge* next;
}edge;

typedef struct
{
   state st;
   edge *e;
}vert;

typedef struct 
{   
	vert  ver[1000] ;
	int vNum;
}adjGraph;

typedef struct
{
	int pos;//pos為該狀態在鄰接表的頂點表中的位置
	int pre;//pre指的是隊中當前元素前驅在qu.dt中的位置
}data;
typedef struct
{
	data dt[1000];
	int front,rear;
}Queue;

//創建頂點表,並記錄所有狀態的個數adj.vNum
void CreteAllState(adjGraph &adj,int m,int n)
{
	for (int c1=0;c1<=1;c1++)
		for(int m1=0;m1<=m;m1++)
			for (int n1=0;n1<=n&&n1<=m1||m1==0&&n1<=n;n1++)//野人要少於修道士人數或全是野人
			{
				adj.ver[adj.vNum].st.s=c1;
				adj.ver[adj.vNum].st.x=m1;
				adj.ver[adj.vNum].st.y=n1;
				adj.ver[adj.vNum].e=NULL;
				cout<<c1<<‘\t‘<<m1<<‘\t‘<<n1<<‘\t‘<<adj.vNum<<endl;
				adj.vNum++;
			}
}
//在頂點表中查找狀態位置(下標)
int SearchState(adjGraph adj,state st)
{
	for (int i=0;i<adj.vNum;i++)
		if(st.s==adj.ver[i].st.s && st.x==adj.ver[i].st.x && st.y==adj.ver[i].st.y)
			return i;
	return -1;
}
int CheckState(adjGraph adj,state st,int m,int n)//判斷st狀態是否可作為第i狀態的後續狀態,如果是則返回後續狀態的位置,否則返回-1;
{
    int pos;state st_OtherSide;
	st_OtherSide.s=st.s==1?0:1;
	st_OtherSide.x=m-st.x;
	st_OtherSide.y=n-st.y;
	pos=SearchState(adj,st_OtherSide);
	if(pos==-1) return -1;
	pos=SearchState(adj,st);
	if(pos==-1) return -1;
	return pos;
}
//創建邊表
void CreateEdges(adjGraph &adj,int m,int n,int c)
{
   edge *t;state st;int j,k,vNo;
   for(int i=0;i<adj.vNum;i++)
   {
		if (adj.ver[i].st.x+adj.ver[i].st.y>0)//修道士與野人總數大於0
		{
			if(adj.ver[i].st.y>0)//假如船上全部為野人
				for (j=1;j<=adj.ver[i].st.y&&j<=c;j++)
				{
					st.s=adj.ver[i].st.s==1?0:1;
					st.x=m-adj.ver[i].st.x;
					st.y=n-(adj.ver[i].st.y-j);
					vNo=CheckState(adj,st,m,n);
					if(vNo==-1) continue; //非法狀態則跳過
					t=new edge;//左岸就往右岸的狀態轉變
					t->verNo=vNo;t->di=st.s;t->x_boat=0;t->y_boat=j;
					t->next=adj.ver[i].e;//頭插法
					adj.ver[i].e=t;
				}
			if(adj.ver[i].st.x>1)//船上有j個修道士與k個野人
				for (j=1;j<=adj.ver[i].st.x&&j<=c;j++)//
				   for (k=0;k<=c-j&&k<=adj.ver[i].st.y;k++)
				   {
						st.s=adj.ver[i].st.s==1?0:1;
						st.x=m-(adj.ver[i].st.x-j);
						st.y=n-(adj.ver[i].st.y-k);
						vNo=CheckState(adj,st,m,n);
						if(vNo==-1) continue;//非法狀態則跳過
						t=new edge;//右岸就往左岸的狀態轉變
						t->verNo=vNo;t->di=st.s;t->x_boat=j;t->y_boat=k;
						t->next=adj.ver[i].e;//頭插法
						adj.ver[i].e=t;
				   }
		}
   }
}



void PrintPath1(adjGraph &adj,Queue &qu,int i)//由i向前找路
{
	if (qu.dt[i].pre!=-1)
	       PrintPath1(adj,qu,qu.dt[i].pre);
	int k=qu.dt[i].pos;
	    cout<<i<<‘\t‘;
	    cout<<adj.ver[k].st.s<<‘\t‘;
		cout<<adj.ver[k].st.x<<‘\t‘;
		cout<<adj.ver[k].st.y<<‘\t‘;
		cout<<endl;
}

void BreadthSearch(adjGraph adj,int* visit,Queue &qu,int x,int y)
{
	int stPos,finPos,tag=1;
	qu.front=qu.rear=-1;
	state st,fin;
	st.s=0;st.x=x;st.y=y;
    stPos=CheckState(adj,st,x,y);
	if(stPos==-1) cout<<"start position error!"<<endl;
	fin.s=1;fin.x=x;fin.y=y;
	finPos=SearchState(adj,fin);
	qu.rear++;
	qu.dt[qu.rear].pos=stPos;//起始位置入隊
	qu.dt[qu.rear].pre=-1;//pre指的是隊中當前元素前驅在qu.dt中的位置
	while(qu.rear!=qu.front&&tag)
	{
		qu.front++;//出隊一元素
		visit[qu.dt[qu.front].pos]=1;
	    if (qu.dt[qu.front].pos==finPos)
	    {
			tag=0;
			cout<<"find the path!"<<endl;
			PrintPath1(adj,qu,qu.front);
			//插入打印路徑的函數
			break;
	    }
		edge *e;
		e=adj.ver[qu.dt[qu.front].pos].e;//e points to the first adjacent edge;
		while (e)
		{
			if(visit[e->verNo]==0)
			{
				qu.dt[++qu.rear].pos=e->verNo;
				qu.dt[qu.rear].pre=qu.front;
			}
			e=e->next;
		}
	}
	if(tag==1)
		cout<<"cant find the path!"<<endl;
	
}

void main()
{
	int m,n,c;//修道士人數,野人人數,船上最多可載人數
	adjGraph adj;Queue qu;
	adj.vNum=0;
	cin>>m>>n>>c;
	CreteAllState(adj,m,n);
	CreateEdges(adj,m,n,c);
	Disp(adj);
	int visit[1000];
	memset(visit,0,sizeof(visit));//把數組置空
BreadthSearch(adj,visit,qu,m,n);
	
}

  

修道士與野人問題(BFS廣度搜索)