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

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

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

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

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

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

可问题是, 电脑并不能理解“羊”的重要性,无法得出优先移动羊的结论。这里我们使用深度搜索(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;
}

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