农夫过河问题——用户自定义初始状态和终止状态

来源:互联网 发布:2017阅读软件排行 编辑:程序博客网 时间:2024/06/08 10:30

问题描述

一个农夫带着一只狼、一只羊和一棵白菜,身处河的南岸,他要把这些东西全部运到北岸。他面前只有一条小船,船只能容下他和一件物品,另外只有农夫才能撑船。如果农夫在场,则狼不能吃羊,羊不能吃白菜;否则狼会吃羊,羊会吃白菜。所以农夫不能留下羊和白菜自己离开,也不能留下狼和羊自己离开,而狼不吃白菜。要求给出农夫将所有的东西运过河的方案。

功能设计

  1. 用户输入起始状态,输入终止状态
  2. 判断输入是否合法
  3. 判断输入的状态是否安全
  4. 获取农夫、狼、白菜、羊的位置
  5. 输出运输方案
  6. 判断是否继续

实现思想

  1. 用4位二进制数顺序分别表示农夫、狼、白菜、羊的位置。0表示在南岸,1表示在北岸
  2. 使用按位与操作来确定每个角色所在位置的代码是0还是1。函数返回值为真,表示在北岸,否则在南岸
  3. 通过位置分布来判断当前状态是否安全。若状态安全返回1,否则返回0
  4. 将初始状态存入队列,并将存储状态路径的数组除初始状态位置置为当前状态所表示的十进制数外全部置为-1,表示未记录过路径
  5. 利用广度优先遍历从初始状态开始依次考虑农夫可能的选择,并判断过河的可能性。如果渡河后状态安全,则将其状态入队并将当前状态的索引记录到路径数组中,下标索引为后续状态值。若渡河后状态不安全,则继续考虑后面一个选择
  6. 若农夫、狼、白菜、羊这四种选择都考虑完成,则将队列中的元素出队,继续考虑新状态下农夫可能的选择和过河的可能性,直到队列为空或者路径数组下标索引值为终止状态的值被访问过了
  7. 从终止状态开始,根据路径数组的下标输出运输方案

代码

#include<stdio.h>#include<stdlib.h>#define MAXSIZE 16typedef int data;typedef struct queue{    data a[MAXSIZE];    int front,rear;        //front队头,rear队尾}SeqQueue, * Seq;// 创建队列Seq create(){    Seq s;    s = (Seq)malloc(sizeof(SeqQueue));    s->front = 0;    s->rear = 0;    return(s);}//判断是否为空int isEmpty(Seq s){    return( s->front == s->rear );}//判断是否为满int isFull(Seq s){    return( (s->rear+1)%MAXSIZE  ==  s->front);}// 入队int insert(Seq s, data x){    if(isFull(s)){        printf("FULL!\n");        return 1;    }    else{        s->a[s->rear] = x;        s->rear = (s->rear + 1) % MAXSIZE;        return 0;    }}// 出队int dele(Seq s, data *d){    if(isEmpty(s)){        printf("Empty!\n");        return 0;    }    else{        *d = s->a[s->front];        s->front = (s->front + 1) % MAXSIZE;        return 1;    }}//将数值进行转换int change(int s){    int f,w,c,g;    f=s/1000;    w=(s%1000)/100;    c=((s%1000)%100)/10;    g=((s%1000)%100)%10;    s=f*8+w*4+c*2+g;    return s;}//判断输入是否正确,正确返回1,否则,返回0int isTrue(int s){    int f,w,c,g;    f=s/1000;    w=(s%1000)/100;    c=((s%1000)%100)/10;    g=((s%1000)%100)%10;    if(f >= 0 && w >= 0 && c >= 0 && g >= 0){        if(f < 2 && w < 2 && c < 2 && g < 2)            return 1;        else            return 0;    }    else        return 0;}//是否继续char isContinue(){    char choice;    printf("\n是否继续?(Y/N)\n");    getchar();    scanf("%c",&choice);    return choice;}//判断农夫的位置,与1000按位与int farmer(int state){    return ((state & 8) != 0);}//判断狼的位置,与0100按位与int wolf(int state){    return ((state & 4) != 0);}//判断白菜的位置,与0010按位与int cabbage(int state){    return ((state & 2) != 0);}//判断羊的位置,与0001按位与int goat(int state){    return ((state & 1) != 0);}// 若状态相容(安全)则返回1,否则返回0int isSafe(int state){    if((goat(state) == cabbage(state)) &&(goat(state) != farmer(state)))  // 羊菜同岸且农夫不在场        return(0);    if((goat(state) == wolf(state)) &&(goat(state) != farmer(state)))  // 狼羊同岸且农夫不在场        return(0);    return(1);}void river(int s,int o){    int route[16];           // 已经考虑的状态路径    int state;               // 当前的状态(二进制)    int newstate;            // 当前的选择会导致的新的状态    int mover;               // 农夫的选择(对应二进制位为1表示选中该乘客)    int print[16]={0};       // 输出结果    int counter, i;    Seq moveTo;    moveTo = create();        // 创建“状态”队列    insert(moveTo,s);         // 初始状态入队    for(i = 0; i < 16; i++){        if(i==s)            route[i] = s;        else            route[i] = -1;        //表示没有记录过路径    }    if(s == o){        printf("\n您已成功到达目标状态!\n");        return;    }    while(!isEmpty(moveTo) && (route[o] == -1)){        if( !dele(moveTo, &state) ){            printf("                        Empty!             \n");        }        // 依次考虑农夫可能的选择:携带羊、白菜和狼,以及农夫只身渡河        //向左位移,mover分别为0001,0010,0100,1000,依次判断过河的可能性        for( mover = 1; mover<= 8; mover <<= 1 ){            if(((state & 8) != 0) == ((state & mover) != 0)){                // 如果农夫与当前选择在河岸的同一侧                newstate = state^( 8|mover ); // 渡河后的情况                if(isSafe(newstate) && (route[newstate] == -1)){                    // 如果渡河后状态安全,则将其状态入队                    route[newstate] = state;  // 将当前状态的索引记录到路径数组中(下标索引为后续状态值)                    insert(moveTo, newstate);                }            }        }    }    // 输出过河策略,0表示在南岸 1表示在北岸    if(route[o] != -1){        counter = 0;        for(state = o; state != s; state = route[state]){            print[counter] = state;            counter++;        }        print[counter] = s;        for(i = counter;i>0;i--){            state= print[i];            newstate = print[i-1];            if(farmer(state) == 0){                printf("                南岸     |                     |     北岸\n");            }            else{                printf("                北岸     |                     |     南岸\n");            }            switch(state^newstate ){            case 12:                printf("                          ----------狼----------         \n");                break;            case 10:                printf("                          ---------白菜---------         \n");                break;            case 9:                printf("                          ----------羊----------         \n");                break;            default:                printf("                          ------什么也不带------         \n");                break;            }        }    }    else        printf("\n无解!\n");}int main(){    int s,o,s1,o1;  //s1,o1为测试输入是否正确    int f,w,c,g;    char choice;    printf("\n                               农夫过河问题\n\n");    do{        do{            //当初始状态输入不正确时重新输入            printf("\n请输入初始状态(农夫 狼 白菜 羊 0表示在南岸,1表示在北岸):\n\n");            scanf("%d",&s);            s1=s;            if(isTrue(s1) == 1){                s = change(s);                if(isSafe(s) == 0){                    printf("\n该状态不安全!\n");                    choice = isContinue();                        if(choice == 'N' || choice == 'n')                            break;                }                else{                    do{                        //当终止状态输入不正确时重新输入                        printf("\n请输入终止状态(农夫 狼 白菜 羊 0表示在南岸,1表示在北岸):\n\n");                        scanf("%d",&o);                        o1=o;                        if(isTrue(o1) == 1){                            o = change(o);                            if(isSafe(o) == 0)                                printf("\n该状态不安全!\n");                            else                                river(s,o);                            choice = isContinue();                            if(choice == 'N' || choice == 'n')                                break;                        }                        else                            printf("\n输入错误!请重新输入!\n");                    }while(isTrue(o1)==0);                }            }            else                printf("\n输入错误!请重新输入!\n");            if(choice == 'N' || choice == 'n')                break;        }while(isTrue(s1) == 0);    }while(choice == 'Y' || choice == 'y');    return 0;}

界面

这里写图片描述

阅读全文
'); })();
0 0
原创粉丝点击
热门IT博客
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 瑞丽诗植发贵吗 瑞丽是哪里的 成都瑞丽装饰 中国云南瑞丽 瑞丽童装批发 瑞丽风格女装 时尚瑞丽杂志 伊美尔瑞丽诗毛发移植 腾冲旅游景点介绍 腾冲有什么好玩的 腾冲市 腾冲旅游攻略自助游攻 滕冲 腾冲县 腾冲图片 云南芒市 芒市 瑞云 瑞云渲染 nike瑞亚 瑞亚手表 瑞仪 瑞佳 瑞信集团 瑞光 瑞光创意工厂 瑞克与莫蒂 瑞克 莫蒂和瑞克 瑞克和莫提 瑞克和莫迪 瑞克与莫迪 瑞克与莫迪第一季 瑞克与莫蒂第一季 瑞克与莫蒂第二部 瑞克与莫蒂第三季 瑞克与莫迪第三季 瑞克与莫迪第三季在线播放 瑞克与莫蒂第三季在线 瑞克与莫迪第二季在线播放 瑞克莫蒂