当前位置:C++技术网 > 资讯 > 数据结构笔记分享:18 农夫过河(图的算法运用)

数据结构笔记分享:18 农夫过河(图的算法运用)

更新时间:2015-12-01 21:35:25浏览次数:1+次

问题描述

一个农夫带着一只狼,一棵白菜和一只山羊要从一条河的南岸到北岸,农夫每次只能带一样东西过过河,但是任意时刻如果农夫不在场时,狼要吃羊、羊要吃菜,请为农夫设计过河方案。

分析:

    要求解农夫过河问题,首先要选择一个对问题中每个角色的位置进行描述的方法。用四位二进制数顺序表表示农夫、狼、白菜和羊的位置。用1表示在南岸,0表示在北岸。共有0000~1111中状态,以每一种状态为图的一个顶点,判断状态中可行的点。

    根据可能出现的情况创建无向图,农夫的运动状态建立邻接矩阵,确定起始状态顶点为状态0000,终结状态顶点为1111,即开始时农夫、狼、羊和白菜都在北岸,顶点状态为0000,运用递归调用深度优先遍历图,从开始状态顶点到结束状态顶点遍历,输出过河情况。

图解

部分代码分析:

以农夫,狼,羊和白菜安全的情况为顶点创建无向图。

 void Graph()
{
for(int i=0;i<MaxSize;i++)
for(int j=0;j<MaxSize;j++)
fwsc[i][j]=0;
for(int farmer=0;farmer<=1;farmer++)
{
for(int wolf=0;wolf<2;wolf++)
{
for(int sheep=0;sheep<2;sheep++)
{
for(int cabbage=0;cabbage<2;cabbage++)
{
if(isSafety(farmer,wolf,sheep,cabbage))
{ k++;
for(int i=k-1;i<k;i++)
vertex[i]=8*farmer+4*wolf+2*sheep+1*cabbage;
for(int i=0;i<k;i++)
{
for(int j=0;j<k;j++)
{
fwsc[i][j]=1;
fwsc[j][i]=1;
}}}}}}}}

深度遍历无向图,并调用递给算法前面

参看《数据结构笔记分享——图的遍历深度优先搜索算法》

看完这些多多尝试自己去实现,确实这个问题当初我也是搞了几天才想明白的,实在不会写的话看源码(c语言实现)

#include "stdio.h"
#include"stdlib.h"

#define MaxVerNum 16                   //最大顶点数

int visited[MaxVerNum];                 //对已访问的顶点标记
int path[MaxVerNum];        //保存DFS搜索到的路径,即与某顶点到下一顶点的路径
int l=1;

typedef struct
{
    int farmer;
    int wolf;
    int sheep;
    int vegetable;
}VextexType;



typedef struct
{
    VextexType  vexs[MaxVerNum];        	//顶点表
	int	edges[MaxVerNum][MaxVerNum];       //邻接矩阵,即边表
    int n;                //顶点数
}MGraph;            //MGraph是以邻接矩阵存储的图类型


int locate(MGraph *G,int F,int W,int S,int V)                   //查找顶点(F,W,S,V)在顶点向量中的位置
{
    int i;
    for(i=0;i<G->n;i++)
        if(G->vexs[i].farmer==F&&G->vexs[i].wolf==W&&G->vexs[i].sheep==S&&G->vexs[i].vegetable==V)
            return (i);             	//返回当前位置
        return (-1);                //没有找到此顶点
}

int is_safe(int F,int W,int S,int V)        //判断状态是否安全
{
    if(F!=S&&(W==S||S==V))  return 0;       //当农夫与羊不在一起,并且狼和羊,羊和菜在一起的时候是不安全的
    else return 1;
}

int is_connected(MGraph *G,int i,int j)         //判断状态i和j之间是否连通
{
    int k=0;
    if(G->vexs[i].wolf!=G->vexs[j].wolf)    k++;
    if(G->vexs[i].sheep!=G->vexs[j].sheep)  k++;
    if(G->vexs[i].vegetable!=G->vexs[j].vegetable)  k++;
    if(G->vexs[i].farmer!=G->vexs[j].farmer&&k<=1)
        return 1;       //以上三个条件不同时满足且农夫状态改变时,返回真,即农夫每次只能带一件东西过船
    else return 0;
}

void CreateG(MGraph *G)
{
    int i,j,F,W,S,V;
    i=0;                    //生成所有安全的图的顶点
    for(F=0;F<=1;F++)
        for(W=0;W<=1;W++)
            for(S=0;S<=1;S++)
                for(V=0;V<=1;V++)
                    if(is_safe(F,W,S,V))
        			{
                        G->vexs[i].farmer=F;
                        G->vexs[i].wolf=W;
                        G->vexs[i].sheep=S;
                        G->vexs[i].vegetable=V;
            			i++;
        			}
    G->n=i;
    for(i=0;i<G->n;i++)
        for(j=0;j<G->n;j++)
            if(is_connected(G,i,j))         //状态i与j之间可以转化,初始化为1,否则为0
                G->edges[i][j]=G->edges[j][i]=1;
        	else
                    G->edges[i][j]=G->edges[j][i]=0;
         //   return 1;
}

void move(MGraph *G,int k,int j)           //状态的文字说明
{
	if(G->vexs[k].wolf!=G->vexs[j].wolf) printf("带狼");
	else if(G->vexs[k].sheep!=G->vexs[j].sheep) printf("带羊"); 
	else if(G->vexs[k].vegetable!=G->vexs[j].vegetable) printf("带白菜");
	else printf("自己");
}


void print_path(MGraph *G,int u,int v)          //输出从u到v之间的简单路径,即顶点序列中不重复的路径
{
    int k,p=1,t=1,j;
    k=u;
	printf("第%d种方法:\n",l++);
    while(k!=v)
    {
        j=k;
		k=path[k];
        printf("\t第%d步:\n",p);
		printf("\t(%d,%d,%d,%d)",G->vexs[k].farmer,G->vexs[k].wolf,G->vexs[k].sheep,G->vexs[k].vegetable);
		printf("农夫");
		move(G,k,j);
		if(t%2==1) printf("到北岸\n");
		else printf("到南岸\n");
        p++;
		t++;
    }

}
 

void DFS_path(MGraph *G,int u,int v)        //深度优先搜素从u到v的简单路径
{
    int j=0;
    visited[u]=1;        //标记已访问过的点
    for(j=0;j<G->n;j++)
	{
		if(G->edges[u][j]&&visited[j]==0)
    	{
            path[u]=j;
            DFS_path(G,j,v);
			if(j==v)  print_path(G,0,9);
    	}
		
	}
	visited[u]--;

}

void main()
{
    int i,j;
    MGraph graph;
    CreateG(&graph);
    for(i=0;i<graph.n;i++)  visited[i]=0;       //置初值
    i=locate(&graph,0,0,0,0);
    j=locate(&graph,1,1,1,1);
    DFS_path(&graph,i,j);

}