修道士与野人问题(BFS广度搜索)

Posted ewitt

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了修道士与野人问题(BFS广度搜索)相关的知识,希望对你有一定的参考价值。

#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广度搜索)的主要内容,如果未能解决你的问题,请参考以下文章

广度优先搜索(BFS)

使用BFS(广度优先搜索)解迷宫类问题

BFS(广度优先搜索)邻接矩阵C ++

在Prolog中使用广度优先搜索(BFS)解决食人族/传教士?

广度优先搜索(BFS)的一个(重要!)细节。

广度优先搜索(BFS)----------------(TjuOj1140_Dungeon Master)