过河问题-狼羊人菜

来源:互联网 发布:nginx 全局变量赋值 编辑:程序博客网 时间:2024/06/05 10:45
/**功能:解决狼羊人过河问题*作者:王文堃*作者邮箱:wenkun_wang@163.com*创建时间:2016/4/5*//*问题描述:有一个人带着一匹狼、一头羊和白菜要过河已知人每次过河只能带一样东西,狼和羊不能单独在一起羊和菜不能单独在一起,求人过河的方案有几种?问题抽象:分别用m、w、g、c来表示人(men)、狼(wolf)、羊(goat)、菜(cabbage)问题的解决步骤:1.求出人狼羊菜在河两岸的所有可能性,排列组合共16种情况,分别是c40:(mwgc|)c41:(wgc|m)、(mgc|w)、(mwc|g)、(mwg|c)c42:(gc|mw)(wc|mg)(wg|mc)(mc|wg)(mg|wc)(mw|gc)c43:(m|wgc)(w|mgc)(g|mwc)(c|mwg)c44:(|mwgc)----------------------------------------------------------2.根据条件去除不可能的状态,将狼羊、羊菜单独在河一边的情况去除,合适情况10种分别是:(mwgc|)(mgc|w)、(mwc|g)、(mwg|c)(wc|mg)、(mg|wc)(w|mgc)、(g|mwc)、(c|mwg)(|mwgc)----------------------------------------------------------3.确定邻接关系,形成一个图,使用邻接矩阵存储【也可使用邻接链表】----------------------------------------------------------4.对图进行遍历,从(mwgc|)出发,用深度优先搜索找到(|mwgc)则为一个可行的方案【也可使用广度优先搜索】*/#include<iostream>#include<fstream>#include<malloc.h>using namespace std;#define datatype char#define ALLSTATE 1#define SELECTSTATE 2#define MAXSIZE 10#define TOLEFT 0#define TORIGHT 1//数据结构说明//记录所有的情况//使用链表是为了后面将错误的状态删除比较方便typedef struct node {    int num; //用来标识情况的序号    datatype state[10]; //用来说明情况    bool IsRight; //用来指示该情况是否符合条件    struct node *next; //指向下一个元素}MyState;typedef struct{    char vertex[MAXSIZE][MAXSIZE]; //顶点    int StateGraph[MAXSIZE][MAXSIZE]; //邻接矩阵}MyGraph;//全局变量声明int num_situation = 0; //统计情况的个数MyState *AllState = (MyState*)malloc(sizeof(MyState)); //创建一个头指针MyState *pEnd = AllState; //用来指示链尾部datatype way[] = { 'm','w','g','c' }; //操作的数组ofstream out("situation.txt"); //用于将所有可能写入文件ifstream in("situation.txt"); //用于从文件中读取所有可能MyGraph *g = (MyGraph*)malloc(sizeof(MyGraph)); //建立图的指针int visited[MAXSIZE]; //用来记录图中一个结点是否被访问过,值为访问它的结点编码//函数声明//-------------------1------------------------------------------------void count_situation(); //计算所有可能的情况void comb(datatype a[], int n, int m, datatype b[], const int M); //组合void file2struct(); //将情况补充后存入结构体void fix(char state[]); //补充情况int output_allstate(int sel); //输出所有情况//-------------------2------------------------------------------------void select_situation(); //筛选情况bool IsRight(char temp[]); //判断该状态是否正确//-------------------3------------------------------------------------void create_graph(); //建立邻接矩阵void init_Graph();void GetNextState(MyState* NowState, int Edge[]); //根据当前状态求后继状态void PassTheBrige(char temp[], char ch, int derction); //ch过河int GetStateNum(char state[]); //获得此状态的编号bool IsEqual(char array1[], char array2[]);void output_graph(); //输出图//-------------------4------------------------------------------------void FindTheAnswer(int start, int end); //找到对应方法void DFS(int s, int e); //找路径void printPath(int e); //输出路径                      char* Num2State(int num); //根据编号返回对应状态void main(){    count_situation(); //第一步:计算所有状态    select_situation(); //第二步:筛选合法状态    create_graph(); //第三步:建立邻接矩阵    FindTheAnswer(GetStateNum("|mwgc"),GetStateNum("wmgc|")); //第四步:深度优先搜索    getchar();}/*------------------------------第一步计算所有情况--------------------------------------*///计算所有可能的情况void count_situation(){    datatype b[4];    out << "|mwgc" << endl;    for (int i = 1; i <= 4; i++)    {        comb(way, 4, i, b, i); //组合    }    out.close();    file2struct(); //将文件中的情况修正后存入结构体    //输出全部结果,并修改状态个数    num_situation = output_allstate(ALLSTATE); }//组合void comb(datatype a[], int n, int m, datatype b[], const int M){    for (int i = n; i >= m; i--)    {        b[m - 1] = i - 1;        if (m > 1)        {            comb(a, i - 1, m - 1, b, M);        }        else //m==1        {            for (int j = M - 1; j >= 0; j--)            {                out << a[b[j]]; //写到文件            }            out << "|" << endl;        }    }}//将情况补充后存入结构体void file2struct(){    int number = 0;    char state[10];    if (in)    {        while (!in.eof())        {            //读取一条状态            in >> state;            //补充状态            fix(state);            //将state保存到结构体中            MyState *temp = (MyState*)malloc(sizeof(MyState));            temp->num = number++;            temp->next = NULL;            strcpy(temp->state, state); //将补充过的状态填入结构体            pEnd->next = temp;            pEnd = temp;        }    }}//补充情况void fix(char state[]){    int i = 0;    bool m = false, w = false, g = false, c = false;    //检查传进来的串种缺少什么元素    while (state[i] != '|')    {        switch (state[i++])        {        case 'm':            m = true;            break;        case 'w':            w = true;            break;        case 'g':            g = true;            break;        case 'c':            c = true;            break;        default:            break;        }    }    //将所有缺少的元素补充到‘|’后面    if (m == false)        state[++i] = 'm';    if (w == false)        state[++i] = 'w';    if (g == false)        state[++i] = 'g';    if (c == false)        state[++i] = 'c';}/*------------------------------第二步判断情况正误--------------------------------------*///筛选情况void select_situation(){    MyState *temp = AllState;    int i = -1;    while (temp->next != NULL)    {        if (!IsRight(temp->next->state)) //如果该状态不正确        {            //将改状态删除            MyState *del = temp->next;            temp->next = del->next;            free(del);        }        else        {            temp->num = i++;            temp = temp->next;        }    }    //输出筛选过的结果,并更新状态个数    num_situation = output_allstate(SELECTSTATE); }//判断该状态是否正确bool IsRight(char temp[]){    int i = 0;    bool m = false, w = false, g = false, c = false;    while (temp[i] != '|' && temp[i] != '\0')    {        switch (temp[i++])        {        case 'm':            m = true;            break;        case 'w':            w = true;            break;        case 'g':            g = true;            break;        case 'c':            c = true;            break;        default:            break;        }    }    //wgc|m    if (w == true && g == true && c == true && m == false)        return false;    //m|wgc    if (m == true && w == false && g == false && c == false)        return false;    //gc|mw    if (g == true && c == true && m == false && w == false)        return false;    //mw|gc    if (m == true && w == true && g == false && c == false)        return false;    //wg|mc    if (w == true && g == true && m == false && c == false)        return false;    //mc|wg    if (m == true && c == true && w == false && g == false)        return false;        return true;}//输出函数int output_allstate(int sel){    int i = 1;    MyState *temp = AllState->next;    if (sel == ALLSTATE)        cout << "-------------所有的情况----------------" << endl;    else if (sel == SELECTSTATE)        cout << "-------------筛选后情况----------------" << endl;    while (temp->next != NULL)    {        cout << "第" << i++ << "种情况:" << temp->state << endl;        temp = temp->next;    }    return i - 1; //返回当前状态的个数}/*------------------------------第三步建立邻接链表--------------------------------------*///建立邻接矩阵/*编程思路:1.根据状态的个数建造一个邻接矩阵2.当状态下一个指针不空的时候,对每一个状态有如下3~6的操作3.求得改状态之后的所有可能状态4.对所有的可能状态进行判断排除可能状态中不满足条件的5.将满足条件的下一个状态与当前状态连边6.下一个状态为当前状态当状态下一个指向为空时图生成完毕*/void create_graph(){    init_Graph();    int Edge[4] = { -1,-1,-1,-1 }; //记录应该链接的边    MyState *temp = AllState->next;    int i = 0;    //遍历状态链表    while (temp->next != NULL)    {        //顶点操作        //给各个顶点赋初值        strcpy(g->vertex[i++], temp->state);        //边操作        //求当前状态每一种满足条件的后继状态        GetNextState(temp,Edge);        //对每一个后记状态进行边添加        for (int j = 0; j < 4; j++)        {            if (Edge[j] != -1) //要加边            {                g->StateGraph[temp->num][Edge[j]] = 111;            }           }        //恢复Edge        for (int j = 0; j < 4; j++)        {            Edge[j] = -1;        }        temp = temp->next;    }    //输出图的邻接矩阵    output_graph();}//初始化图void init_Graph(){    for (int i = 0; i < 10; i++)    {        for (int j = 0; j < 10; j++)        {            g->StateGraph[i][j] = 0;        }    }}//根据当前状态求后继状态void GetNextState(MyState* NowState, int Edge[]){    //判断当前状态中人的位置    int i_Edge = 0;    int i = 0;    bool m = false, w = false, g = false, c = false;    //保存NowState    char Copy[10];    strcpy(Copy, NowState->state);    while (NowState->state[i] != '|' && NowState->state[i] != '\0')    {        switch (NowState->state[i++])        {        case 'm':            m = true;            break;        case 'w':            w = true;            break;        case 'g':            g = true;            break;        case 'c':            c = true;            break;        default:            break;        }    }    //人在河左    if (m == true)    {        //狼在河左,带狼过        if (w == true)        {            PassTheBrige(Copy, 'w', TORIGHT);            PassTheBrige(Copy, 'm', TORIGHT);            if (IsRight(Copy))            {                Edge[i_Edge++] = GetStateNum(Copy);            }            strcpy(Copy, NowState->state);        }        //羊在河左,带羊过        if (g == true)        {            PassTheBrige(Copy, 'g', TORIGHT);            PassTheBrige(Copy, 'm', TORIGHT);            if (IsRight(Copy))            {                Edge[i_Edge++] = GetStateNum(Copy);            }            strcpy(Copy, NowState->state);        }        //菜在河左,带菜过        if (c == true)        {            PassTheBrige(Copy, 'c', TORIGHT);            PassTheBrige(Copy, 'm', TORIGHT);            if (IsRight(Copy))            {                Edge[i_Edge++] = GetStateNum(Copy);            }            strcpy(Copy, NowState->state);        }        //人自己过河        PassTheBrige(Copy, 'm', TORIGHT);        if (IsRight(Copy))        {            Edge[i_Edge++] = GetStateNum(Copy);        }        strcpy(Copy, NowState->state);    }    else //人在河右    {        //狼在河右,带狼过        if (w == false)        {            PassTheBrige(Copy, 'w', TOLEFT);            PassTheBrige(Copy, 'm', TOLEFT);            if (IsRight(Copy))            {                Edge[i_Edge++] = GetStateNum(Copy);            }            strcpy(Copy, NowState->state);        }        //羊在河左,带羊过        if (g == false)        {            PassTheBrige(Copy, 'g', TOLEFT);            PassTheBrige(Copy, 'm', TOLEFT);            if (IsRight(Copy))            {                Edge[i_Edge++] = GetStateNum(Copy);            }            strcpy(Copy, NowState->state);        }        //菜在河左,带菜过        if (c == false)        {            PassTheBrige(Copy, 'c', TOLEFT);            PassTheBrige(Copy, 'm', TOLEFT);            if (IsRight(Copy))            {                Edge[i_Edge++] = GetStateNum(Copy);            }            strcpy(Copy, NowState->state);        }        //人自己过河        PassTheBrige(Copy, 'm', TOLEFT);        if (IsRight(Copy))        {            Edge[i_Edge++] = GetStateNum(Copy);        }        strcpy(Copy, NowState->state);    }}//过河函数,将temp数组中的字母ch移动到‘|’对岸void PassTheBrige(char temp[], char ch, int derction){    int i = 0, j = 0;    //找ch的位置    for (i = 0; i < 5; i++)    {        if (temp[i] == ch)            break;    }    //将ch删除    for (j = i; j < 5; j++)    {        temp[j] = temp[j + 1];    }    //找河的位置    for (i = 0; i < 5; i++)    {        if (temp[i] == '|')            break;    }    if (derction == TORIGHT)    {        temp[4] = ch; //给最后一个    }    else //过到河左    {        for (j = 4; j >= i; j--)        {            temp[j + 1] = temp[j];        }        temp[i] = ch;    }}//获得此状态的num编号int GetStateNum(char state[]){    MyState* temp = AllState->next;    while (temp->next != NULL)    {        if (IsEqual(temp->state,state))        {            return temp->num;        }        else        {            temp = temp->next;        }    }    return -1;}//判断两个状态是否相等bool IsEqual(char array1[], char array2[]){    int i = 0;    bool m1 = false, w1 = false, g1 = false, c1 = false;    bool m2 = false, w2 = false, g2 = false, c2 = false;    while (array1[i] != '|' && array1[i] != '\0')    {        switch (array1[i++])        {        case 'm':            m1 = true;            break;        case 'w':            w1 = true;            break;        case 'g':            g1 = true;            break;        case 'c':            c1 = true;            break;        default:            break;        }    }    i = 0;    while (array2[i] != '|' && array2[i] != '\0')    {        switch (array2[i++])        {        case 'm':            m2 = true;            break;        case 'w':            w2 = true;            break;        case 'g':            g2 = true;            break;        case 'c':            c2 = true;            break;        default:            break;        }    }    if (m1 == m2 && w1 == w2 && g1 == g2 && c1 == c2)        return true;    else        return false;}//输出图void output_graph(){    int i = 0, j = 0;    cout << endl;    cout << "-------------邻接矩阵为----------------" << endl;    cout << "   ";    for (i = 0; i < 10; i++)    {        cout << g->vertex[i] << "   ";    }    cout << endl;    for (i = 0; i < 10; i++)    {        cout << g->vertex[i] << "   ";        for (j = 0; j < 10; j++)        {            cout << g->StateGraph[i][j]<<"  ";        }        cout << endl;        cout << endl;    }    cout << endl;}/*------------------------------第四步进行深度搜索--------------------------------------*///找路径void FindTheAnswer(int start, int end){    //初始化    for (int i = 0; i < MAXSIZE; i++)    {        visited[i] = -1;    }    visited[start] = start;    cout << endl;    cout << "-------------最终结果为----------------" << endl;    DFS(start, end);}//深度优先搜索void DFS(int s, int e){    if (s == e)    {        printPath(e);        cout << endl;    }    for (int i = 1; i < MAXSIZE; i++)    {        if (g->StateGraph[s][i] > 0 && visited[i] == -1) //有边且没有被访问        {            visited[i] = s; //标志边被s点访问            DFS(i, e);             visited[i] = -1; //回溯后修改边为未被访问        }    }}//输出void printPath(int e){    if (visited[e] != e)    {        printPath(visited[e]);        cout << "-->";    }    //输出e所对应的状态    cout << " (" << Num2State(e) << ") ";}//根据编号返回对应状态char* Num2State(int num){    MyState* temp = AllState->next;    while (temp->next != NULL)    {        if (temp->num == num)        {            return temp->state;        }        else        {            temp = temp->next;        }    }    return NULL;}

最终的结果为:
这里写图片描述
这里写图片描述

0 0
原创粉丝点击