人羊狼菜过河问题c++

原本我的队长就推荐我写一些自己的博客作为参考供笔记用,再加上昨天我发老师也鼓励我们要写博客,就借这个契机开始写我自己的博客吧。

本篇我想就老师课后留的一个问题展开,该问题如下:

有一个农夫,一头羊,一头狼,一捆菜在河的一头,问农夫有多少种方式将它们运到河对岸?这个问题还有一点限制,那就是:农夫不在时,狼会吃羊,羊会吃菜,形成了一条食物链。

这个题中的元素有农夫、羊、狼、菜、河流、船。在这个问题里河流自始至终状态没变,可以忽略不计。而且只有农夫可以驾驶船,因此可以将农夫和船看成一个元素。

乍一看问题的关键就在这头羊,只要将羊带走就能破坏这条食物链。由此可推方法如下:

先将羊移到对岸,空手回来,再将狼(此时狼和菜等权重)移到对岸,并且将羊移回来(防止狼吃羊),之后将菜移到对岸,最后将羊移到对岸即可。同理,可以将上述方法中的狼与菜互换,由此可得两种方法。

可问题是, 电脑并不能理解“羊”的重要性,无法得出优先移动羊的结论。这里我们使用深度搜索(dfs)的方法,让电脑找到所有移动的方法,再利用限制条件进行剪枝,帮助电脑找到正确方法。

首先,要表达元素们“过河”与“未过河”两种状态。我决定用bool的true与false来表达这两种状态。F代表农民,V代表蔬菜,S代表羊,W代表狼,"."表示空位。其定义如下:

bool F, W, G, V; 

根据老师的问题,初始状态是固定的(所有元素都在河的一边),结束状态则是元素全都移到另一边。操作便是“运输”,我们用“->”表示将要运送的方式。

输入样例

输出格式

如果无解,输出”-1“;
若有解,则输出所有可能的解法(由若干行状态组成)
解法间空一行

输出样例

FWGV -> ....
.W.V <- F.G.
FW.V -> ..G.
...V <- FWG.
F.GV -> .W..
..G. <- FW.V
F.G. -> .W.V
.... <- FWGV

FWGV -> ....
.W.V <- F.G.
FW.V -> ..G.
.W.. <- F.GV
FWG. -> ...V
..G. <- FW.V
F.G. -> .W.V
.... <- FWGV

此处解法排列顺序按照——空手——狼——羊——菜的顺序。

解题思路

状态表示确定,算法用深度优先遍历。建立一个二维char数组q,每一步遍历都往q中存放当前状态。由于要避免出现两行相同的状态,还应建立一个bool数组fl来检查当前状态是否存在过。

代码实现

#include <stdio.h>
#include <string.h>
#include <iostream>

using namespace std;

const int N = 1010;

bool F, W, V, S;
int flag; // 判断是否找到方法
char q[N][20];//存储每一次运输后的状态
bool fl[20];//判断改状态是否出现过

void pr(int x)
{
     if(F) q[x][8] = 'F';
     else q[x][0] = 'F';
     if(W) q[x][9] = 'W';
     else q[x][1] = 'W';
     if(V) q[x][10] = 'V';
     else q[x][2] = 'V';
     if(S) q[x][11] = 'S';
     else q[x][3] = 'S';
}

void book(bool F, bool W, bool V, bool S)
{
    //标记该状态已经出现过
      if(F &&W && V && S) fl[0] = true;
      else if(!F && W && V && S) fl[1] = true;
      else if(F && !W && V && S) fl[2] = true;
      else if(F && W && !V && S) fl[3] = true;
      else if(F && W && V && !S) fl[4] = true;
      else if(!F && !W && V && S) fl[5] = true;
      else if(!F && W && !V && S) fl[6] = true;
      else if(!F && W && V && !S) fl[7] = true;
      else if(F && !W && !V && S) fl[8] = true;
      else if(F && !W && V && !S) fl[9] = true;
      else if(F && W && !V && !S) fl[10] = true;
      else if(!F && !W && !V && S) fl[11] = true;
      else if(!F && !W && V && !S) fl[12] = true;
      else if(!F && W && !V && !S) fl[13] = true;
      else if(F && !W && !V && !S) fl[14] = true;
      else if(!F && !W && !V && !S) fl[15] = true;
}

void dfs(int x)
{
    if((W == S && W != F) || (V == S && V != F))       //不可能情况返回
    {
        dfs(x + 1);
         return ; 
    }
    
     if(F && W && V && S)       //全部过河时打印所有可能性
     {
      flag = 1;
      for(int i = 0 ; i < x; i ++ )
      {
       printf("%s", q[i]);
      }
      puts("");
      return ;
     }
     
     for(int i = 1; i <= 4; i ++ )
     {
      
      char sps[20] = ".... -> ....";
      char sps2[20] = ".... <- ....";
      if(!F) strcpy(q[x], sps);
      else strcpy(q[x], sps2);
    
      if(!F)
      {
           F = true;  //农夫过河
           if(i == 1 && W != F && (!fl[0] || !fl[3] || !fl[4] || !fl[10] ))
           {
                   W = true;
                   book(F, W, V, S);
                   pr(x);
                  dfs(x + 1);
                  F = false;
                  W = false;         //状态复原
           }
           else if(i == 2 && V != F && (!fl[0] || !fl[2] || !fl[4] || !fl[9] ))
           {
                   V = true;
                   book(F, W, V, S);
                   pr(x);
                  dfs(x + 1);
                  F = false;
                  V = false;
           }
           else if(i == 3 && S != F && (!fl[0] || !fl[2] || !fl[3] || !fl[8] ))
           {
                   S = true;
                   book(F, W, V, S);
                   pr(x);
                  dfs(x + 1);
                  F = false;
                  S = false;
           }
           else if(i == 4)
           {
                   book(F, W, V, S);
                   pr(x);
                  dfs(x + 1);
                  F = false;
           }
      }
      else
      {
           F = false;  //农夫回岸
           if(i == 1 && W != F && (!fl[5] || !fl[11] || !fl[12] || !fl[15] ))
           {
                   W = false;
                   book(F, W, V, S);
                   pr(x);
                  dfs(x + 1);
                  F = true;
                  W = true;
           }
           else if(i == 2 && V != F && (!fl[6] || !fl[11] || !fl[13] || !fl[15] ))
           {
                   V = false;
                   book(F, W, V, S);
                   pr(x);
                  dfs(x + 1);
                  F = true;
                  V = true;
           }
           else if(i == 3 && S != F && (!fl[7] || !fl[12] || !fl[13] || !fl[15] ))
           {
                   S = false;
                   book(F, W, V, S);
                   pr(x);
                  dfs(x + 1);
                  F = true;
                  S = true;
           }
           else if(i == 4)
           {
                   book(F, W, V, S);
                   pr(x);
                  dfs(x + 1);
                  F = true;
           }
      }
      
      
      
      
     }
 
 
}

int main()
{
     char sps[20] = "FWGV -> ....";
     strcpy(q[0], sps);
     
     dfs(0);
     
     if(flag != 1) puts("-1");     //未找到方法时输出-1
     return 0;
}

这里有一个问题:输出为空,经测试是因为他没有到达最终妇科条件并输出的那条路,希望未来的我能回来把他给解决掉~

人羊过河问题是一个经典的逻辑推理问题,可以使用Java代码进行分析和解决。以下是一个简单的Java代码示例,通过深度优先搜索(DFS)算法来解决该问题。 ```java import java.util.*; public class RiverCrossingProblem { // 定义人羊过河问题的初始状态 private static final int LEFT = 0; private static final int RIGHT = 1; private static final int[] INIT_STATE = {LEFT, LEFT, LEFT, LEFT}; // 定义人羊过河问题的目标状态 private static final int[] GOAL_STATE = {RIGHT, RIGHT, RIGHT, RIGHT}; // 定义人、羊、的编号 private static final int PERSON = 0; private static final int SHEEP = 1; private static final int WOLF = 2; private static final int VEGETABLE = 3; // 定义人羊过河问题的状态 private static class State { int[] items; int boat; State parent; public State(int[] items, int boat, State parent) { this.items = items; this.boat = boat; this.parent = parent; } public boolean isGoal() { return Arrays.equals(items, GOAL_STATE); } public List<State> getNextStates() { List<State> nextStates = new ArrayList<>(); for (int i = 0; i < items.length; i++) { if (items[i] != boat) continue; int[] nextItems = items.clone(); nextItems[i] = 1 - nextItems[i]; if (isValidState(nextItems)) { nextStates.add(new State(nextItems, 1 - boat, this)); } for (int j = i + 1; j < items.length; j++) { if (items[j] != boat) continue; int[] nextItems2 = nextItems.clone(); nextItems2[j] = 1 - nextItems2[j]; if (isValidState(nextItems2)) { nextStates.add(new State(nextItems2, 1 - boat, this)); } } } return nextStates; } private boolean isValidState(int[] items) { if (items[SHEEP] == items[WOLF] && items[PERSON] != items[SHEEP]) { return false; } if (items[VEGETABLE] == items[SHEEP] && items[PERSON] != items[VEGETABLE]) { return false; } return true; } } // 使用深度优先搜索算法来解决人羊过河问题 public static void solve() { Stack<State> stack = new Stack<>(); Set<String> visited = new HashSet<>(); State initState = new State(INIT_STATE, LEFT, null); stack.push(initState); visited.add(Arrays.toString(initState.items)); while (!stack.isEmpty()) { State currentState = stack.pop(); if (currentState.isGoal()) { printPath(currentState); return; } for (State nextState : currentState.getNextStates()) { if (!visited.contains(Arrays.toString(nextState.items))) { stack.push(nextState); visited.add(Arrays.toString(nextState.items)); } } } System.out.println("No solution found!"); } // 打印求解路径 private static void printPath(State state) { List<String> path = new ArrayList<>(); while (state != null) { path.add(Arrays.toString(state.items)); state = state.parent; } Collections.reverse(path); for (String s : path) { System.out.println(s); } } public static void main(String[] args) { solve(); } } ``` 在上述代码中,我们首先定义了人羊过河问题的初始状态和目标状态,以及人、羊、的编号。然后,我们定义了一个`State`类来表示人羊过河问题的状态,包括当前状态下的物品位置、船的位置和父状态。`State`类还包括了判断当前状态是否为目标状态、获取下一步状态的方法以及判断状态是否合法的方法。 接下来,我们使用深度优先搜索算法来解决人羊过河问题。我们首先定义了一个栈和一个HashSet,用于存储当前搜索路径和已经访问过的状态。然后,我们从初始状态开始搜索,每次从栈中弹出一个状态,并查找该状态下所有可能的下一步状态。如果某个下一步状态是合法的且之前没有访问过,那么将其压入栈中,并将其添加到已访问状态的HashSet中。如果找到了目标状态,则打印求解路径;否则,输出“No solution found!”。最后,在`main`方法中调用`solve`方法来求解人羊过河问题。 需要注意的是,上述代码只是一个简单的示例,还有许多可以改进的地方,例如使用广度优先搜索算法、优化搜索过程等等。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值