过河问题-狼羊人菜
来源:互联网 发布: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
- 过河问题-狼羊人菜
- 过河问题
- 过河问题
- 过河问题
- 过河问题
- 过河问题
- 过河问题
- 过河问题
- 过河问题
- 过河问题
- 过河问题
- 过河问题
- 过河问题
- 过河问题
- 过河问题
- 过河问题
- 过河问题
- 过河问题
- 最长公共子串-不建立dp数组(空间复杂度为O(1))
- 3dMAX的导出文件格式
- 使用appearance proxy定制控件的默认外观(详解)
- VB.net版机房收费系统——结账功能实现(代码部分)
- 住院费用查询--按照病案核算分类计算
- 过河问题-狼羊人菜
- leetcode---Same Tree
- 【Android基础】四种点击事件
- LTE-TDD随机接入过程(3)-RAR(MSG2)以及MSG1的重传
- 【使用JSOUP实现网络爬虫】修改数据-设置元素的文本内容
- powerdesigner设置对象颜色
- 比较字符串是否相等
- VC运行时提示 "0x7c9569da"指令引用的“0x00000000”内存,该内存不能为"read"
- C++第三次实验——作业