思路:用0/1代表所处位置,农夫、狼、羊、菜过河就是0000->1111,一共是16种状态,去掉其中的不可能的状态如0011(羊和菜单独一起)是10种。
可以用图的方式表示:

clipboard.png
或者用树的方式表示
clipboard.png

简单代码实现如下:

package algorithm;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.IntStream;

public class CrossRiver {
    static int farmer = 0, wolf = 1, sheep = 2, cabbage = 3;
    static int start = 0, end = 15;
    static List<String> listResult = new ArrayList<String>();

    static boolean cross(int[] conds) {
        for (int curr : conds) {
            // 跳过已发生的状态
            if (listResult.contains("" + curr)) continue;
            
            listResult.add("" + curr);
            // 如已找到解,则返回
            if (curr == end) return true;

            // 找到可以转化的状态
            int[] nexts = IntStream.range(0, 16).filter(item -> isValid(curr, item)).toArray();
            // 如所有状态都无解,则移除当前步骤
            if (!cross(nexts)) listResult.remove("" + curr);
            // 如已找到解,则直接返回
            if(listResult.contains("" + end)) return true;
        }
        return false;
    }

    // 是否满足条件
    static boolean isValid(int curr, int next) {
        if (position(curr, farmer) == position(next, farmer)) {
            return false;
        } // 农夫没过河
        if (position(next, wolf) == position(next, sheep) & position(next, farmer) != position(next, wolf)) {
            return false;
        } // 狼羊单独
        if (position(next, sheep) == position(next, cabbage) & position(next, farmer) != position(next, sheep)) {
            return false;
        } // 羊菜单独
        if (position(curr, farmer) != position(curr, wolf) & position(curr, wolf) != position(next, wolf)) {
            return false;
        } // 狼不在身边不能带着过河
        if (position(curr, farmer) != position(curr, sheep) & position(curr, sheep) != position(next, sheep)) {
            return false;
        } // 羊不在身边不能带着过河
        if (position(curr, farmer) != position(curr, cabbage) & position(curr, cabbage) != position(next, cabbage)) {
            return false;
        } // 菜不在身边不能带着过河
        if (Math.abs(curr - next) != 8 & Math.abs(curr - next) != 9 & Math.abs(curr - next) != 10
                & Math.abs(curr - next) != 12) {
            return false;
        } // 超载或其他情况
        return true;
    }

    // 获取位置
    static char position(int i, int pos) {
        String tmp = Integer.toBinaryString(i);
        tmp = ("0000" + tmp).substring(tmp.length());
        return tmp.charAt(pos);
    }

    static void print() {
        String out = "";
        String east = "东岸:";
        String west = "西岸:";
        if (position(15, farmer) == 0) {
            east += "农夫 ";
        } else {
            west += "农夫 ";
        }
        if (position(15, wolf) == 0) {
            east += "狼 ";
        } else {
            west += "狼 ";
        }
        if (position(15, sheep) == 0) {
            east += "羊 ";
        } else {
            west += "羊 ";
        }
        if (position(15, cabbage) == 0) {
            east += "菜 ";
        } else {
            west += "菜 ";
        }
        out += east + "\n" + west + "\n";
        System.out.println(out);
    }

    public static void main(String[] args) {
        //把农夫、狼、羊、菜过河看作从0000 -> 1111的变化
        int[] conditions = { start };
        cross(conditions);

        listResult.stream().forEach(item -> {
            String tmp = Integer.toBinaryString(Integer.valueOf(item));
            tmp = ("0000" + tmp).substring(tmp.length());
            System.out.print(tmp + " ");
        });
    }
}

innate
15 声望2 粉丝