Home
  • 计算机网络
  • 操作系统
  • 数据结构与算法
  • 设计模式
  • JavaSE
  • JVM
  • JUC
  • Netty
  • CPP
  • QT
  • UE
  • Go
  • Gin
  • Gorm
  • HTML
  • CSS
  • JavaScript
  • vue2
  • TypeScript
  • vue3
  • react
  • Spring
  • SpringMVC
  • Mybatis
  • SpringBoot
  • SpringSecurity
  • SpringCloud
  • Mysql
  • Redis
  • 消息中间件
  • RPC
  • 分布式锁
  • 分布式事务
  • 个人博客
  • 弹幕视频平台
  • API网关
  • 售票系统
  • 消息推送平台
  • SaaS短链接系统
  • Linux
  • Docker
  • Git
GitHub (opens new window)
Home
  • 计算机网络
  • 操作系统
  • 数据结构与算法
  • 设计模式
  • JavaSE
  • JVM
  • JUC
  • Netty
  • CPP
  • QT
  • UE
  • Go
  • Gin
  • Gorm
  • HTML
  • CSS
  • JavaScript
  • vue2
  • TypeScript
  • vue3
  • react
  • Spring
  • SpringMVC
  • Mybatis
  • SpringBoot
  • SpringSecurity
  • SpringCloud
  • Mysql
  • Redis
  • 消息中间件
  • RPC
  • 分布式锁
  • 分布式事务
  • 个人博客
  • 弹幕视频平台
  • API网关
  • 售票系统
  • 消息推送平台
  • SaaS短链接系统
  • Linux
  • Docker
  • Git
GitHub (opens new window)
  • 哈希表

  • 双指针

  • 数组

  • 字符串

  • 链表

  • 树

  • 回溯

  • 动态规划

  • 图

    • DFS
    • BFS
    • 并查集
    • 拓扑排序
    • 0-1BFS
    • 最短路
    • 最小生成树Kruskal
    • 图论
    • 状态机
      • 野人与传教士渡河
      • 365. 水壶问题
  • 二分查找

  • 贪心

  • 栈&队列

  • 堆

  • 位运算

  • 数据结构设计

  • rui的精选题单

  • 笔试真题

  • LeetCode周赛

  • ACM模式输入输出
  • 数学

  • 数据结构与算法
  • 图
Nreal
2024-04-20
目录

状态机

# 野人与传教士渡河

两岸的野人数<=传教士人数;

必须有人驾船;

public class Cross {
    static class State{
        int y;
        int c;
        int dir;
        int by;
        int bc;
        public State(int y, int c, int dir, int by, int bc) {
            this.y = y;
            this.c = c;
            this.dir = dir;
            this.by = by;
            this.bc = bc;
        }
    }
    static List<State> route = new LinkedList<>();
    static int yNum;
    static int cNum;
    static int boatNum;
    static boolean[][][] vis;

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        yNum = sc.nextInt();
        cNum = sc.nextInt();
        boatNum = sc.nextInt();
        vis = new boolean[yNum+1][cNum+1][2]; // 左岸野人,左岸传教士,方向 0向右 1向左
        vis[yNum][cNum][0] = true;
        State s = new State(yNum,cNum,0,0,0);
        route.add(s);
        move(yNum,cNum,0);
    }

    // 左岸野人,左岸传教士,方向
    public static void move(int y,int c,int dir){
        if(y==0 && c==0){
            System.out.println("===================================");
            for(State state:route){
                if(state.dir==1){
                    System.out.println("左岸的传教士:"+state.c+" 野人:"+state.y+" 船上的传教士:"+state.bc+" 野人:"+state.by);
                }else{
                    if(state.bc!=0 || state.by!=0){
                        System.out.println("船上的传教士:"+state.bc+" 野人:"+state.by+" 右岸的传教士:"+(cNum-state.c)+" 野人:" + (yNum-state.y));
                    }
                }
            }
            System.out.println();
            return ;
        }
        // 向右岸渡河
        if(dir==0){
            // 渡河野人数量
            for(int i=0;i<=boatNum;i++){
                // 渡河传教士数量
                for(int j=0;j<=boatNum-i;j++){
                    // 船上必须有人
                    if(i+j>=1){
                        // 渡河后,左岸传教士>=野人 , 或传教士为0
                        if(y-i <= c-j || c-j==0){
                            // 渡河后,当左岸野人数>=0
                            if(y-i>=0 && !vis[y-i][c-j][1]){
                                // 船到右岸后,右岸加船上的传教士数>=野人数 或 传教士=0
                                if(yNum-y+i <= cNum-c+j || cNum-c+j==0){
                                    vis[y-i][c-j][1] = true;
                                    State s = new State(y-i,c-j,1,i,j);
                                    route.add(s);
                                    move(y-i,c-j,1);
                                    vis[y-i][c-j][1] = false;
                                    route.remove(s);
                                }
                            }
                        }
                    }
                }
            }
        }else{
            for(int i=0;i<=boatNum;i++){
                for(int j=0;j<=boatNum-i;j++){
                    if(i+j>=1){
                        // 渡河后,右岸传教士 >= 野人数 或 传教士为0
                        if(yNum-y-i <= cNum-c-j || cNum-c-j==0){
                            // 渡河后,左岸传教士和野人不能超过最大值
                            if(y+i<=yNum && c+j<=cNum && !vis[y+i][c+j][0]){
                                // 船到左岸后,左岸加船上的传教士>野人数 或 传教士为0
                                if(y+i<=c+j || c+j==0){
                                    vis[y+i][c+j][0] = true;
                                    State s = new State(y+i,c+j,0,i,j);
                                    route.add(s);
                                    move(y+i,c+j,0);
                                    vis[y+i][c+j][0] = false;
                                    route.remove(s);
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100

# 365. 水壶问题 (opens new window)

class Solution {
    public boolean canMeasureWater(int x, int y, int z) {
        // 特判
        if (z == 0) {
            return true;
        }
        if (x + y < z) {
            return false;
        }

        State initState = new State(0, 0);

        // 广度优先遍历使用队列
        Queue<State> queue = new LinkedList<>();
        Set<State> visited = new HashSet<>();

        queue.offer(initState);
        visited.add(initState);

        while (!queue.isEmpty()) {
            State head = queue.poll();

            int curX = head.getX();
            int curY = head.getY();

            // curX + curY == z 比较容易忽略
            if (curX == z || curY == z || curX + curY == z) {
                return true;
            }

            // 从当前状态获得所有可能的下一步的状态
            List<State> nextStates = getNxtState(curX, curY, x, y);
            
            // 打开以便于观察,调试代码
            // System.out.println(head + " => " + nextStates);
            
            for (State nextState : nextStates) {
                if (!visited.contains(nextState)) {
                    queue.offer(nextState);
                    // 添加到队列以后,必须马上设置为已经访问,否则会出现死循环
                    visited.add(nextState);
                }
            }
        }
        return false;
    }
    List<State> getNxtState(int curX,int curY,int x,int y){
        List<State> list = new ArrayList<>(8);
        State s1 = new State(x,curY); // 将x加满
        State s2 = new State(curX,y); // 将y加满
        State s3 = new State(0,curY); // 将x清空
        State s4 = new State(curX,0); // 将y清空
        State s5 = new State(curX-(y-curY),y); // X倒满Y,X还有剩
        State s6 = new State(0,curX+curY); // X倒给Y,X没剩
        State s7 = new State(x,curY-(x-curX)); // Y倒满X,Y还有剩
        State s8 = new State(curX+curY,0); // Y倒给X,Y没剩
        // 没有满才需要倒水
        if(curX<x)
            list.add(s1);
        if(curY<y)
            list.add(s2);

        // 有水才能清空
        if(curX>0)
            list.add(s3);
        if(curY>0)
            list.add(s4);
        
        // 有剩余才倒
        if(curX-(y-curY)>0)
            list.add(s5);
        if(curY-(x-curX)>0)
            list.add(s7);
        
        // 倒过去倒不满
        if(curX+curY<y)
            list.add(s6);
        if(curX+curY<x)
            list.add(s8);

        return list;
    }
    class State{
        int x;
        int y;
        public State(int x,int y){
            this.x = x;
            this.y = y;
        }
        public int getX() {
            return x;
        }

        public int getY() {
            return y;
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
图论
二分边界问题

← 图论 二分边界问题→

Theme by Vdoing | Copyright © 2021-2024
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式