图论08-图的建模-状态的表达与理解 - 倒水问题为例

这篇具有很好参考价值的文章主要介绍了图论08-图的建模-状态的表达与理解 - 倒水问题为例。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

状态的表达

例题1

图论08-图的建模-状态的表达与理解 - 倒水问题为例,图论,图论

从初始的(x,y)状态,到最后变成(4,?)或者(?,4).

本道题对于(x,y)的状态,可以使用10x+y进行表达,也就是变成了一个数字,分别放在不同的数位上。
但是本状态的表示方法不适用单个数组超过9的,因为一个数位只能表示0-9.。

涉及思想:状态压缩

题解

1 终止条件:有一个数位为4

if(next / 10 == 4 || next % 10 == 4) {
    end = next;
    return;
}

2 状态的改变:a表示十位数,b表示个位数

重复添加满水不影响结果

a = cur / 10, b = cur % 10;

要达到(4,?)或者(?,4)的办法文章来源地址https://www.toymoban.com/news/detail-740789.html

  • a桶灌满5升水
  • b桶灌满3升水
  • a桶的水倒掉
  • b桶的水倒掉
  • a桶中的水倒进b桶中 --> 最多能倒a升,还能倒b桶剩余空闲容量=(3-b桶当前容量)
  • b桶中的水倒进a桶中
nexts.add(5 * 10 + b);
nexts.add(a * 10 + 3);
nexts.add(a * 10 + 0);
nexts.add(0 * 10 + b);

int x = Math.min(a, 3 - b);
nexts.add((a - x) * 10 + (b + x));

int y = Math.min(b, 5 - a);
nexts.add((a + y) * 10 + (b - y));

3 其他设置

  • 访问数组用于记录访问过的状态
 boolean[] visited = new boolean[100];
  • 队列用于记录访问的每个节点的状态
Queue<Integer> queue = new LinkedList<>();
  • 记录上一个状态
pre = new int[100];
  • 记录状态变化
    • 首先要把pre数组填好,根据pre数组将遍历的过程从最终结果向前找初始状态。最终再翻转链表。
    • 做标记 设置end = -1
      如果end倒最后还是-1,说明问题没有解。
import java.util.*;
import java.util.ArrayList;

public class WaterPuzzle {

    private int[] pre;
    private int end = -1;

    public WaterPuzzle(){

        Queue<Integer> queue = new LinkedList<>();
        boolean[] visited = new boolean[100];
        pre = new int[100];

        queue.add(0);
        visited[0] = true;
        while (!queue.isEmpty()){
            int cur = queue.remove();
            int a = cur / 10, b = cur % 10;
            // max a = 5, max b = 3

            ArrayList<Integer> nexts = new ArrayList<>();
            nexts.add(5 * 10 + b);
            nexts.add(a * 10 + 3);
            nexts.add(a * 10 + 0);
            nexts.add(0 * 10 + b);

            int x = Math.min(a, 3 - b);
            nexts.add((a - x) * 10 + (b + x));

            int y = Math.min(b, 5 - a);
            nexts.add((a + y) * 10 + (b - y));

            for(int next: nexts)
                if(!visited[next]){
                    queue.add(next);
                    visited[next] = true;
                    pre[next] = cur;

                    if(next / 10 == 4 || next % 10 == 4) {
                        end = next;
                        return;
                    }
                }
        }
    }

    public Iterable<Integer> result(){

        ArrayList<Integer> res = new ArrayList<>();
        if(end == -1) return res;

        int cur = end;
        while(cur != 0){
            res.add(cur);
            cur = pre[cur];
        }
        res.add(0);
        Collections.reverse(res);
        return res;
    }

    public static void main(String[] args){
        System.out.println((new WaterPuzzle()).result());
    }
}

例题2 力扣773 滑动谜题

Java

/// Leetcode 773

import java.util.ArrayList;
import java.util.Queue;
import java.util.LinkedList;
import java.util.HashMap;


public class Solution {

    private int[][] dirs = {{-1, 0}, {0, 1}, {1, 0}, {0, -1}};

    public int slidingPuzzle(int[][] board) {

        Queue<String> queue = new LinkedList<>();
        HashMap<String, Integer> visited = new HashMap<>();

        String initalState = boardToString(board);
        if(initalState.equals("123450")) return 0;

        queue.add(initalState);
        visited.put(initalState, 0);
        while(!queue.isEmpty()){
            String cur = queue.remove();

            ArrayList<String> nexts = getNexts(cur);

            for(String next: nexts)
                if(!visited.containsKey(next)){
                    queue.add(next);
                    visited.put(next, visited.get(cur) + 1);
                    if(next.equals("123450"))
                        return visited.get(next);
                }
        }
        return -1;
    }

    private ArrayList<String> getNexts(String s){

        int[][] cur = stringToBoard(s);

        int zero;
        for(zero = 0; zero < 6; zero ++)
            if(cur[zero / 3][zero % 3] == 0)
                break;

        ArrayList<String> res = new ArrayList<>();
        int zx = zero / 3, zy = zero % 3;
        for(int d = 0; d < 4; d ++){
            int nextx = zx + dirs[d][0], nexty = zy + dirs[d][1];
            if(inArea(nextx, nexty)){
                swap(cur, zx, zy, nextx, nexty);
                res.add(boardToString(cur));
                swap(cur, zx, zy, nextx, nexty);
            }
        }
        return res;
    }

    private boolean inArea(int x, int y){
        return x >= 0 && x < 2 && y >= 0 && y < 3;
    }

    private void swap(int[][] board, int x1, int y1, int x2, int y2){
        int t = board[x1][y1];
        board[x1][y1] = board[x2][y2];
        board[x2][y2] = t;
    }

    private String boardToString(int[][] board){
        StringBuilder sb = new StringBuilder();
        for(int i = 0; i < 2; i ++)
            for(int j = 0; j < 3; j ++)
                sb.append(board[i][j]);
        return sb.toString();
    }

    private int[][] stringToBoard(String s){
        int[][] board = new int[2][3];
        for(int i = 0; i < 6; i ++)
            board[i / 3][i % 3] = s.charAt(i) - '0';
        return board;
    }

    public static void main(String[] args){

        int[][] board = {{1, 2, 3}, {4, 0, 5}};
        System.out.println((new Solution()).slidingPuzzle(board));
    }
}

C++

class Solution {
public:
    int slidingPuzzle(vector<vector<int>>& board) {
//记录最终状态
    const string sol = "123450";

    const int m = 2, n = 3;
    const int dirs[4][2] = {{-1, 0}, {0, 1}, {1, 0}, {0, -1}};

//记录初始状态,使用字符串记录
    string init;
    for (auto &line: board) {
        for (auto &grid: line) {
            init.push_back('0' + grid);
        }
    }

//构造队列,并初始化
    queue<string> q{{init}};

//设置unordered_set,记录访问状态
    unordered_set<string> vis{{init}};

//记录步数
    int ans = 0;

//开始BFS
    while (!q.empty()) {
        int size = q.size();
        for (int i = 0; i < size; ++i) {
            auto &p = q.front();
            //出口
            if (p == sol) {
                return ans;
            }

            //先找0号的位置
            int idx0 = p.find('0');

            //四联通拓展
            for (int a = 0; a < 4; ++a) {
                //求0号元素的二维新坐标
                int nx = idx0 / n + dirs[a][0], ny = idx0 % n + dirs[a][1];
                //求0号元素映射到一维数组中的坐标
                int idx1 = nx * n + ny;
                //判断边界
                if (nx >= 0 && nx < m && ny >= 0 && ny < n) {
                    //交换两个元素的位置
                    swap(p[idx0], p[idx1]);
                    //如果当前状态没有测试过
                    if (!vis.count(p)) {
                        //加入访问数组
                        vis.insert(p);
                        //入队
                        q.push(p);
                    }
                    //恢复原来的状态,继续交换位置然后将状态入队列
                    swap(p[idx0], p[idx1]);
                }
            }
        q.pop();
        }
    //对头出队的时候,开始移动到下一个状态,因此步数+1
    ++ans;
    }
    return -1;
    }
};

到了这里,关于图论08-图的建模-状态的表达与理解 - 倒水问题为例的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 图论_(1)_图的基本概念

    图(graph) 是由顶点集合和顶点间的二元关系集合(即边的集合或弧的集合)组成的数据结构,通常可以用 G ( V , E ) G(V,E) G ( V , E ) 表示 顶点集合(vertext set) 用 V ( G ) V(G) V ( G ) 表示,其中元素称为 顶点(vertex) ,用 u 、 v u、v u 、 v 等符号表示。 边的集合(edge set) 用 E ( G ) E(G) E ( G

    2024年02月05日
    浏览(49)
  • 离散数学-图论-图的基本概念(11)

    1.1 图的定义 定义1: 一个 无向图 G是一个有序的二元组V,E,其中 (1)V是一个非空有穷集,称为顶点集,其元素称为顶点或结点。 (2)E是无序积VV的有穷多重子集,称为边集,其元素称为无向边,简称边。 定义2: 一个 有向图 D是一个有序的二元组V,E,其中 (1)V是一个非

    2024年02月13日
    浏览(49)
  • 图论 (Java) 从入门到入土 /第一部分 图的基础-图的表示/

            图,是一种比较复杂的数据结构。和树的一个节点只和上层一个节点相连不同,在图中,任意两个节点都可能相连,且可能具有方向性,并且节点的边具有权重,因此,图被用于描述各种复杂的数据对象,在自然科学、社会科学和人文科学等诸多领域有着非常广泛

    2024年02月08日
    浏览(43)
  • 图论与算法(2)图的基本表示

    (1) 有向图和无向图: 有向图(Directed Graph):图中的边具有方向,表示节点之间的单向关系。 无向图(Undirected Graph):图中的边没有方向,表示节点之间的双向关系。 (2)加权图和无权图: 加权图(Weighted Graph):图中的边具有权重或距离,表示节点之间的关系有一定

    2024年02月04日
    浏览(48)
  • 图论-图的基本概念与数据结构

    无向图 边是没有方向的,也就是双向的 结点 V = { v 1 , v 2 , . . . , v 7 } mathcal{V} = { v_1,v_2,...,v_7} V = { v 1 ​ , v 2 ​ , ... , v 7 ​ } 边 ε = { e 1 , 2 , e 1 , 3 , . . . , e 6 , 7 } varepsilon = {e_{1,2},e_{1,3},...,e_{6,7}} ε = { e 1 , 2 ​ , e 1 , 3 ​ , ... , e 6 , 7 ​ } 图 G = { V , ε } mathcal{G} = { math

    2024年02月08日
    浏览(52)
  • 图论专栏一《图的基础知识》

    图论(Graph Theory)是数学的一个分支 。它以图为研究对象。图论中的图是由若干给定的点及连接两点的线所构成的图形,这种图形通常用来描述某些实体之间的某种特定关系,用点代表实体,用连接两点的线表示两个实体间具有的某种关系。 相比矩阵、张量、序列等结构,

    2024年02月03日
    浏览(40)
  • 图论与算法(3)图的深度优先遍历

    图的遍历 是指按照一定规则访问图中的所有顶点,以便获取图的信息或执行特定操作。常见的图遍历算法包括深度优先搜索(DFS)和广度优先搜索(BFS)。 深度优先搜索 (DFS):从起始顶点开始,递归或使用栈的方式访问相邻的顶点,直到所有顶点都被访问过为止。DFS通过

    2024年02月06日
    浏览(50)
  • 图论与算法(5)图的广度优先遍历应用

    树的广度优先遍历(Breadth-First Traversal),也称为层次遍历,是一种按层次顺序逐级访问树节点的遍历方式。在广度优先遍历中,先访问树的根节点,然后按照从上到下、从左到右的顺序逐层访问树的节点。 首先将树的根节点入队列,然后循环执行以下操作:出队列一个节点

    2024年02月08日
    浏览(46)
  • 图论01-【无权无向】-图的基本表示-邻接矩阵/邻接表

    https://github.com/Chufeng-Jiang/Graph-Theory/tree/main/src/Chapt01_Adjacency 代码有删减 代码有删减 只需要改动一行 adj = new TreeSet[V]; //构造邻接表, V行,V个LinkedList 代码有删减

    2024年02月07日
    浏览(44)
  • 【图论】图的概念和基本术语(顶点、边、度、路径等)

    在数学和计算机科学中,图是由 顶点(节点) 和 边(连接) 组成的一种 数据结构 ,用于描述对象之间的关系。图是一种广泛应用于许多领域的数学概念,包括计算机科学、网络分析、运筹学、社交网络分析等。 图可以用于表示各种现实世界中的问题,如社交网络中的用户

    2024年02月07日
    浏览(56)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包