C++:农夫过河问题

农夫、羊、菜和狼的故事

题目描述

有一个农夫带一只羊、一筐菜和一只狼过河。如果没有农夫看管,则狼要吃羊,羊要吃菜。但是船很小,只够农夫带一样东西过河。问农夫该如何解此难题?

输入描述:

题目没有任何输入。

输出描述:

题目可能有种解决方法,求出步骤最少的解决方法,
按顺序输出农夫想把羊、菜、狼全部运过河需要哪几个步骤。
如果需要将羊带过河去则输出“sheep_go”。
如果需要将羊带回来则输出“sheep_come”。
如果需要将菜带过河去则输出“vegetable_go”。
如果需要将菜带回来则输出“vegetable_come”。
如果需要将狼带过河去则输出“wolf_go”。
如果需要将狼带回来则输出“wolf_come”。
如果需要空手返回则输出“nothing_come”。
如果需要空手过河则输出“nothing_go”。
每输出一种方案,输出一行“succeed”。

解题思路

农夫过河问题,用0000的二进制分别代表河的一岸的农夫、羊、菜、狼,假如农夫带狼过河则0000变为1001。
总共有16种状态,每次过河的操作(8种操作)都会变成另外一个状态,直到得到1111,可以得到一个状态树,保存满足条件的路径。
不满足题目要求的状态有1001(9),0110(6),1000(8),1010(10),0101(5),0111(7),即5~10都不合法。
建立一个当前搜索队列,保存遍历的状态,出现重复的状态则不进行这次变化(避免死循环),若队尾出现0,退出搜索。

解决代码

#include<iostream>
#include<queue>
using namespace std;
queue<int> q;
int visit[20];//用来保存当前状态的前一状态,注意不能直接int visit[20]={-1}初始化,初始化成0可以,但其他数字要用循环老老实实一个一个赋值
int a[4]={8,12,10,9};//用来表示4种状态转换操作:8(1000)——nothing;12(1100)——sheep;10(1010)——vegetable;9(1001)——wolf。

bool judge(int x){//用来判断是否为合法状态
     if(x>=5&&x<=10) return false; 
     else if(x>15 || x<0) return false;
     else if(visit[x]!=-1) return false;
     else return true;
 }
 
void BFS(){ //树的广度搜索,寻找最短路径
     int current=q.front();
     q.pop();
     for(int i=0;i<4;i++ ){  //每次有四种选择,空船,带羊,带菜,带狼
         int next=a[i]^current; //异或运算,相同为0,不同为1,即求出当前的运动状态
         if(judge(next)){    
	         q.push(next);
	         visit[next]=current; //visit[当前状态]=当前状态的前一个状态
	         if(next == 15) return; //15(1111)
         }
     }
     BFS();
 }
 
void print_result(int a,int b){
    switch(b-a){
        case -8:cout<<"nothing_come"<<endl;break;
        case -12:cout<<"sheep_come"<<endl;break;
        case -10:cout<<"vegetable_come"<<endl;break;
        case -9:cout<<"wolf_come"<<endl;break;
        case 8:cout<<"nothing_go"<<endl;break;
        case 12:cout<<"sheep_go"<<endl;break;
        case 10:cout<<"vegetable_go"<<endl;break;
        case 9:cout<<"wolf_go"<<endl;break;
    }
}
 int main(){
     int start=0;
     for(int i=0;i<16;i++) visit[i]=-1; //初始化16种状态
     q.push(start); //从0000开始
     visit[start]=-2; //标记源节点
     BFS();
     int x=15; //15(1111)
     int re[20];//根据visit数组来获得路径顺序,即状态序列
     int index=0;
     while(x!=-2){
         re[index++]=x;
         x=visit[x];
     }
     for(int i=index-1;i>0;i--){//根据a数组即状态序列的变换打印状态转换过程
            print_result(re[i],re[i-1]);
     }
     cout<<"succeed"<<endl;
     return 0;
 }
  • 6
    点赞
  • 56
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值