通过深度优先,宽度优先,A*来求解8数码难题JAVA版(已经实现)

在这里插入图片描述
BFS实现过程

  1. 定义队列,用于存储每一步的棋盘状态
  2. 开局寻找到空格的位置,然后以0123的顺序进行遍历,0123分别代表向下,向左,向上,向右.
  3. 每向一个方向走一步,便将四个到达这一步后的所有方向放进队列,然后再从队列中获取新的情况进行遍历,由于队列先进先出FIFO的特点,所以进行实现了BFS的搜索.
  4. 如果队列内有重复的情况,便不再进队,经过这样处理能够大幅度减少遍历的过程,而且报证了遍历的时间是有限的,因为棋盘的总情况只有9!种情况.(由于可达性的问题,如果可达,情况很更少一些)
    DFS实现过程
    1.定义栈,用于存储每一步的棋盘状态
  5. 开局寻找到空格的位置,然后以0123的顺序进行遍历,0123分别代表向下,向左,向上,向右.
  6. 如果按照原本的深度优先搜索,会不停的进行压栈处理,因为在八数码难题,树的深度可以是9!,即直到找完所有情况,或者找到解才会停止.同样进行BFS第四步的操作,可以保证最终可以搜索到解,因为情况有限.但是在算法实现中,由于不停的进行压栈却不出栈,会导致计算机内存溢出,无法执行结果.
    4.针对3,使用了深度受限的深度搜索,设定长度为30(由于BFS已经搜索出结果,为了更快出结果,所以将深度设置的更浅)
    5.但在实际运行中,由于深度优先搜索的会从下往上,而BFS由BFS的结果会知道,DFS结果由于一开始的搜索方向便没有往解的方向搜索,因此运行时间太长,为了减少等待时间,继续对其优化.
    6.采用BFS与DFS相结合的方法.将栈定义为双向队列.当BFS搜索的达到限制深度以后,不在出栈,而是出队,即取出第一个进入的元素进行深度优先搜索,因此等待时间变得可接受,当然,当换一种情况以后便不一定起到减少时间的作用.
    A*搜索
    1.定义一个优先级队列来存储每一步的状态
  7. 定义f(n)=g(n)+h(n)为初始状态经由状态n到目标状态的代价估计.g(n)为实际代价,在我的程序中即为当前路径长度,g(n)在A*算法中,我采用的是非常简化的估计,不在目标位置的数字数量.在后面的遗传算法中,为了提高遗传算法的效率,计算遗传算法的适应度使用的g(n)是每个数字到目标位置的曼哈顿距离.
    3.使用BFS算法进行遍历每个方向,与之不同的是,这是一个优先队列,会对每个入队状态排序,损失越低的排的越前,即越接近目标状态g(n)越小的会越优先遍历.
    遗传算法
    群体智能算法中,我选用了遗传算法.
    1.为了方便算法,遗传算法中,路径换了一种方式进行表达,用0123代表空格向下左上右方向进行移动.
    2.在八数码难题中,以路径为基因.本题中,基因长度为100.随机生成0-3的100个数字作为一个染色体.注:如果当空格沿着路径走,碰到边界无法走以后,将会忽略该基因(不表达).
    3.我采用的适应度计算方式为150-每个数字的曼哈顿距离-不在正确位置的位置数-正确的最短路径长度.计算过程,从第一个基因开始走路,并计算到当前基因为止的计算适应度,直到走到目标状态,即可能出现基因长度的一半便到达目标状态的情况.
    曼哈顿距离:
    目标状态 每个位置的编码
    012 012
    456 456
    789 789
    曼哈顿距离的计算,每个数字当前位置到目标位置需要移动的步数

4.每个参数的设置,种群个数为100,染色体基因长度为100,交换率为0.95,变异率为0.02精英遗传个体数为5.遗传最大代数为10000.
5.每代采用轮盘赌算法进行亲代选择
(六) 实验结果与分析说明
BFS结果:
12
345
678
[4, 4, 3, 0, 1, 4, 7, 6, 3, 4, 5, 2, 1, 0, 3, 4, 5, 8, 7, 6, 3, 4, 5, 2, 1, 4, 3, 0] 28

由于程序设计原因,第二个数字不算在内,从第三步开始,即3开始,总共26步走到目标状态.
内存为213909504字节 时间为475721ms
DFS结果
12
345
678
[4, 4, 3, 6, 7, 4, 5, 8, 7, 4, 3, 6, 7, 4, 1, 2, 5, 4, 1, 0, 3, 4, 1, 2, 5, 8, 7, 4, 3, 0] 30
解释同BFS,共27步走到目标结果.

内存122558824字节 时间143528ms
A*结果
12
345
678
[4, 4, 3, 0, 1, 4, 7, 6, 3, 4, 5, 2, 1, 0, 3, 4, 5, 8, 7, 6, 3, 4, 5, 2, 1, 4, 3, 0] 28
最终解和BFS搜索相同,即最短路径
内存35115520字节
时间8349ms

说明:
数字表了空格的位置,九宫格每个位置进行了编号,为:
012 724 一开始空格的位置为4, 724
345 初始棋盘为 5 6 [4,3]代表了空格向左走 56
678 831 即: 831
遗传算法

染色体
2333203100303112231113232030031122232011230032122322332333300132130130310123333212012033003003011222
第85步走到目标解
内存使用92917072字节 运行时间3346ms
在截图的实验中,种群的总适应度由初始的2700逐渐上升至4600左右.
分析:
1.关于BFS,由于从浅层开始搜索,当情况的数量有限时,一定能找到解且一定是最优解.缺点是当解深度较大、情况过多时,时间会比较漫长。而且与初始遍历的顺序也会有关系。改进可以考虑使用双向宽度搜索。
2.关于DFS,由于从深层开始搜索,所以搜索到的结果大概率不是最优解,而且与初始遍历的顺序有关,同样的,当情况较多时,搜索时间很漫长。由此演化而来的搜索方法,深度受限搜索。改进方法可以是BFS、DFS相结合进行搜索。
3.遗传算法,遗传算法利用了生物进化的原理,能够在有限时间内搜索出比较好的结果。但是容易陷入局部最优解,但是合理的设置参数可以减少这种情况的发生。在实际使用过程中,一般会将遗传算法同其他算法一同配合使用,如模拟退火算法和遗传算法相结合进行使用。
感悟和收获:
人工智能也是一门有较长历史的学科,有很多和数学交叉的地方。比如在数学建模中,人工智能的算法常常会使用到,或者说人工智能的算法本身也是一种建模过程,在学习人工智能方法的过程中,经常也会在数学建模这门课程见到同一个算法的应用。本学期除了选修了人工智能同样选修了数学建模,在人工智能学习到的算法很快的就能在数学建模中上手应用,而应用的过程又加深了对算法的理解。
关于选用JAVA语言的原因,由于本学期课程正在学习JAVA语言,所以选用JAVA语言其实也是想锻炼一下JAVA语言的编程水平,而且在编程过程中确实踩了很多坑,比如深拷贝和浅拷贝的问题,但由于这是人工智能的实验报告,因此就不太好在实验报告中进行总结了。
本学期也借由这一章学到的几个算法,参加了一个有关资源最优分配的项目设计,使用到了遗传算法以及模拟退火。在本次实验报告编写和项目的参与过程中,开始尝试使用计算机的视角去解决问题,例如BFS和DFS搜索,在我的直观感觉中是暴力的,不具备数学美感的解法,然而或许就是计算机的这种暴力(非常夸张的运算能力),成就了计算机算法之美叭,以上仅为个人一点感悟。

BFS、DFS、A*算法代码
package AI1;

import java.util.*;

public class ChessBoard {
    //0往下走,1往左走,2往上走,3往右走
    static public Queue<ChessBoard> queue = new LinkedList<>();
    static public Deque<ChessBoard> stack = new ArrayDeque<>();
    static public Queue<ChessBoard> pqueue = new PriorityQueue<>(new Comparator<ChessBoard>() {
        @Override
        public int compare(ChessBoard o1, ChessBoard o2) {
            return o1.cost-o2.cost;
        }
    });
    public static List<String> been = new ArrayList<>();//存储遍历过的图形

    public int flag = 0;
    public char[][] chessBoard = new char[3][3];
    public int x, y;
    public List<Integer> history = new ArrayList<>();
    private int cost = 1000;


    ChessBoard() {
        chessBoard = new char[][]{{'7', '2', '4'},
                {'5', ' ', '6'},
                {'8', '3', '1'}};
//        chessBoard = new char[][]{{' ', '1', '2'}, {'3', '4', '5'}, {'6', '7', '8'}};
        findspace();
        history.add(x + 3 * y);
        history.add(x + 3 * y);
        findcost();
    }


    public ChessBoard(ChessBoard cb) {
        for (int i = 0; i < 3; i++) {
            for (int i1 = 0; i1 < 3; i1++) {
                this.chessBoard[i][i1] = cb.chessBoard[i][i1];
            }
        }

        findspace();
        findcost();
        for (int t : cb.history) {
            history.add(t);
        }

    }


    public void tonext() {
        switch (flag) {
            case 0:
                todown();
                flag++;
            case 1:
                toleft();
                flag++;
            case 2:
                toup();
                flag++;
            case 3:
                toright();
                flag++;
        }

    }


    private boolean todown() {
        ChessBoard cb = new ChessBoard(this);
        if (y != 2 && (((y + 1) * 3 + x) != history.get(history.size() - 2))) {
            cb.chessBoard[y][x] = cb.chessBoard[y + 1][x];
            cb.chessBoard[y + 1][x] = ' ';
            cb.findspace();
            cb.findcost();
            cb.history.add(cb.x + cb.y * 3);
            pqueue.offer(cb);
            queue.offer(cb);
            stack.push(cb);
            return true;
        }
        return false;
    }

    private boolean toleft() {
        ChessBoard cb = new ChessBoard(this);
        if (x != 0 && ((y * 3 + x - 1) != history.get(history.size() - 2))) {
            cb.chessBoard[y][x] = cb.chessBoard[y][x - 1];
            cb.chessBoard[y][x - 1] = ' ';
            cb.findspace();
            cb.history.add(cb.x + cb.y * 3);
            cb.findcost();
            pqueue.offer(cb);
            queue.offer(cb);
            stack.push(cb);
            return true;
        }
        return false;
    }

    private boolean toup() {
        ChessBoard cb = new ChessBoard(this);
        if (y != 0 && (((y - 1) * 3 + x) != history.get(history.size() - 2))) {
            cb.chessBoard[y][x] = cb.chessBoard[y - 1][x];
            cb.chessBoard[y - 1][x] = ' ';
            cb.findspace();
            cb.history.add(cb.x + cb.y * 3);
            cb.findcost();
            pqueue.offer(cb);
            stack.push(cb);
            queue.offer(cb);
            return true;
        }
        return false;
    }

    private boolean toright() {
        ChessBoard cb = new ChessBoard(this);
        if (x != 2 && ((y * 3 + x + 1) != history.get(history.size() - 2))) {
            cb.chessBoard[y][x] = cb.chessBoard[y][x + 1];
            cb.chessBoard[y][x + 1] = ' ';
            cb.findspace();
            cb.history.add(cb.x + cb.y * 3);
            cb.findcost();
            pqueue.offer(cb);
            stack.push(cb);
            queue.offer(cb);
            return true;
        }
        return false;
    }

    public void findspace() {
        for (int i = 0; i < 3; i++) {
            for (int i1 = 0; i1 < 3; i1++) {
                if (chessBoard[i][i1] == ' ') {
                    this.y = i;
                    this.x = i1;
                }
            }
        }
    }
    public void findcost(){
        int flag=0;
        char num = '0';
        for (int i = 0; i < 3; i++) {
            for (int i1 = 0; i1 < 3; i1++) {
                if (i == 0 && i1 == 0) {
                    if (chessBoard[i][i1] != ' ')
                        flag++;
                } else {
                    if (chessBoard[i][i1] != num)
                       flag++;
                }
                num++;
            }
        }
        cost = flag + history.size();
    }

    public boolean right() {
        char num = '0';
        for (int i = 0; i < 3; i++) {
            for (int i1 = 0; i1 < 3; i1++) {
                if (i == 0 && i1 == 0) {
                    if (chessBoard[i][i1] != ' ')
                        return false;
                } else {
                    if (chessBoard[i][i1] != num)
                        return false;
                }
                num++;
            }
        }
        return true;
    }

    public void displaychessBoard() {
        for (int i = 0; i < 3; i++) {
            System.out.println(chessBoard[i]);
        }
        System.out.println(history+"  "+history.size());
    }

    static void DFS() {
        String s = "";
        ChessBoard cb = new ChessBoard();
        for (char a[] : cb.chessBoard)
            for (char a1 : a)
                s += a1;
        been.add(s);
        s = "";
        int i = 0;
        while (!cb.right()) {
            cb.tonext();
            do {
                cb = ChessBoard.stack.pop();
//                cb.displaychessBoard();
                while (cb.history.size() > 30)
                    cb = ChessBoard.stack.pollLast();
                for (char a[] : cb.chessBoard)
                    for (char a1 : a)
                        s += a1;
            }
            while (been.contains(s));
            been.add(s);
            s = "";
            if(i%10000==0) {
                cb.displaychessBoard();
                i = 0;
            }
            i++;
        }
        cb.displaychessBoard();
    }

    static void BFS() {
        String s = "";
        ChessBoard cb = new ChessBoard();
        for (char a[] : cb.chessBoard)
            for (char a1 : a)
                s += a1;
        been.add(s);
        s = "";
        int i = 0;
        while (!cb.right()) {
            cb.tonext();
            do {
                cb = ChessBoard.queue.poll();
                for (char a[] : cb.chessBoard)
                    for (char a1 : a)
                        s += a1;
//                cb.displaychessBoard();
            }
            while (been.contains(s));
            been.add(s);
            s = "";
            if(i%10000==0) {
                cb.displaychessBoard();
                i = 0;
            }
            i++;
        }
        cb.displaychessBoard();
    }
    static void Astar() {
        String s = "";
        ChessBoard cb = new ChessBoard();
        for (char a[] : cb.chessBoard)
            for (char a1 : a)
                s += a1;
        been.add(s);
        s = "";
        int i = 0;
        while (!cb.right()) {
            cb.tonext();
            do {
                cb = ChessBoard.pqueue.poll();
                for (char a[] : cb.chessBoard)
                    for (char a1 : a)
                        s += a1;
//                cb.displaychessBoard();
            }
            while (been.contains(s));
            been.add(s);
            s = "";
            if(i%10000==0) {
                cb.displaychessBoard();
                i = 0;
            }
            i++;
        }
        cb.displaychessBoard();
    }
}
测试类
package AI1;
public class Main {
    public static void main(String[] args) {
        long startTime=System.currentTimeMillis();   //获取开始时间
        ChessBoard.DFS();
        long endTime=System.currentTimeMillis(); //获取结束时间
        Runtime s_runtime = Runtime.getRuntime();
        System.out.println("内存:"+(s_runtime.totalMemory() - s_runtime.freeMemory())+"字节" );
        System.out.println("时间:"+(endTime-startTime)+"ms");
    }
}
遗传算法代码
package AI1pulsplus;

import java.util.*;

public class ChessBoard {
    //个体数100,基因长度为100的种群
    Individual[] zhongqun;
    int alladaption;


    ChessBoard() {
        zhongqun = new Individual[100];
        for (int i = 0; i < 100; i++) {
            zhongqun[i] = new Individual();
        }
        for (int i = 0; i < 10000; i++) {
            this.jinhua();
            for (int j = 0; j < 100; j++) {
                zhongqun[j].dnashow();
            }
            alladaption();
            if (i % 50 == 0) {
                System.out.print(alladaption + " ");
                System.out.println();
//                for (int q=0;q<100;q++) {
//                    System.out.print(zhongqun[q].adaption+" ");
//                }
//                System.out.println();
            }
        }
        System.out.println(alladaption);
        for (int i = 0; i < 100; i++) {
            System.out.print(zhongqun[i].adaption + " ");
        }
//        System.out.println();
//        for (int i = 0; i < 5; i++) {
//            for (int t : zhongqun[i].dna)
//                System.out.print(t);
//            System.out.println();
//        }
        int size = Individual.list.size();
        Collections.sort(Individual.list);
        System.out.println();
        System.out.println("adaption:");
        for (Individual a:Individual.list)
            System.out.print(a.adaption+" ");
        System.out.println();

        System.out.println("size:"+Individual.list.size());

        for (int t : Individual.list.get(size-1).dna)
                System.out.print(t);
        System.out.println();
        System.out.println("location:"+Individual.list.get(size-1).right);
    }

    void jinhua() {
        alladaption();
        double temp;
        double leiji;
        Individual[] newdna = new Individual[100];
        int t = 0;
//        for (int i = 0; i < 100; i++) {
//            newdna[i] = new Individual();
//        }
        while (t != 100) {
            leiji = 0;
            temp = Math.random();
            Individual[] dna1 = new Individual[100];
            int z = 0;
            for (int i = 0; i < 100; i++) {
                leiji += (zhongqun[i].adaption * 1.0) / (alladaption * 1.0);
                if (leiji > temp) {
                    dna1[z] = new Individual(zhongqun[i]);
//                    System.out.println(dna1[z]==zhongqun[i]);
                    z++;
                }
            }
            for (int i = 0; i < z - 1; i++) {
                int start = (int) (Math.random() * 101);
                if (100 - start < 20)
                    start = 80;
//                for(int q:dna1[i].dna)
//                    System.out.print(q);
//                System.out.println("11111");
                cross(dna1[i].dna, dna1[i + 1].dna, start, 20);
                newdna[t] = new Individual(dna1[i]);
//                System.out.println(newdna[t]==dna1[i]);
//                for(int q:dna1[i].dna)
//                    System.out.print(q);
//                System.out.println("11111");
                t++;
                if (t == 100) break;
            }
        }
        Arrays.sort(zhongqun);
        for (int i = 0; i < 5; i++)
            newdna[95 + i] = new Individual(zhongqun[95 + i]);

        for (int i = 0; i < 100; i++)
            zhongqun[i] = new Individual(newdna[i]);
        shuffle(zhongqun);
        bianyi();

    }

    public static void shuffle(Individual[] nums) {
        Random rnd = new Random();
        for (int i = nums.length - 1; i > 0; i--) {
            int j = rnd.nextInt(i + 1);
            //swap index i, j
            Individual t = nums[i];
            nums[i] = nums[j];
            nums[j] = t;
        }
    }

    void bianyi() {
        for (int i = 0; i < 100; i++) {
            if (Math.random() > 0.98) {
                int start = (int) (Math.random() * 101);
                int len = (int) (Math.random() * (100 - start));
                for (int t = start; t < start + len; t++) {
                    zhongqun[i].dna[t] = (int) (Math.random() * 4);
                }
            }
        }
    }

    void alladaption() {
        alladaption = 0;
        for (int i = 0; i < 100; i++)
            alladaption += zhongqun[i].adaption;
    }


    void cross(int[] a, int b[], int start, int len) {
        for (int i = start; i < start + len; i++) {
            int t = a[i];
            a[i] = b[i];
            b[i] = t;
        }
    }
}

class Individual implements Comparable {


    @Override
    public int compareTo(Object o) {
        Individual o1 = (Individual) o;
        if (this.adaption < o1.adaption)
            return -1;
        else if (this.adaption > o1.adaption)
            return 1;
        else
            return 0;
    }


    static int[][] manhattan = {
            {0, 1, 2, 1, 2, 3, 2, 3, 4},//0
            {1, 0, 1, 2, 1, 2, 3, 2, 3},//1
            {2, 1, 0, 3, 2, 1, 4, 3, 2},//2
            {1, 2, 3, 0, 1, 2, 1, 2, 3},//3
            {2, 1, 2, 1, 0, 1, 2, 1, 2},//4
            {3, 2, 1, 2, 1, 0, 3, 2, 1},//5
            {2, 3, 4, 1, 2, 3, 0, 1, 2},//6
            {3, 2, 3, 2, 1, 2, 1, 0, 1},//7
            {4, 3, 2, 3, 2, 1, 2, 1, 0} //8
    };//曼哈顿距离
    //0往下走,1往左走,2往上走,3往右走
    static int[] x = {0, -1, 0, 1};
    static int[] y = {1, 0, -1, 0};

    public int space_x = 1, space_y = 1;
    public int[][] chessBoard = {{7, 2, 4}, {5, 0, 6}, {8, 3, 1}};
    //    public int[][] chessBoard = {{0, 1, 2}, {3, 4, 5}, {6, 7, 8}};
    public int dna[] = new int[100];
    public int adaption;
    public int right = 100;
    static List<Individual>list = new LinkedList<>();

    Individual() {
        for (int i = 0; i < 100; i++) {
            dna[i] = (int) (Math.random() * 4);
        }
        dnashow();

    }

    Individual(Individual a) {
        for (int i = 0; i < 100; i++)
            this.dna[i] = a.dna[i];
        this.right = a.right;
        this.space_x = a.space_x;
        this.space_y = a.space_y;
        this.adaption = a.adaption;
        this.chessBoard = a.chessBoard;
    }

    boolean right() {
        int q = 0;
        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 3; j++) {
                if (chessBoard[i][j] != q)
                    return false;
                q++;
            }
        }
        return true;
    }

    void dnashow() {
        for (int i = 0; i < 100; i++) {
            if (space_x + x[dna[i]] >= 0 && space_x + x[dna[i]] < 3 && space_y + y[dna[i]] >= 0 && space_y + y[dna[i]] < 3) {
                int temp = chessBoard[space_y + y[dna[i]]][space_x + x[dna[i]]];
                chessBoard[space_y + y[dna[i]]][space_x + x[dna[i]]] = 0;
                chessBoard[space_y][space_x] = temp;
                space_x += x[dna[i]];
                space_y += y[dna[i]];
//                displaychessBoard();
            }
            if (right()) {
//                for (int x : dna)
//                    System.out.print(x);
                right = i+1;
//                System.out.println("找到了:" + right);
                adaption();
                list.add(new Individual(this));
//                System.out.println();
//                displaychessBoard();
            }
            adaption();
        }

        chessBoard = new int[][]{{7, 2, 4}, {5, 0, 6}, {8, 3, 1}};
        space_x = 1;
        space_y = 1;
    }

    void jianyan(int q) {
        for (int i = 0; i < q; i++) {
//            System.out.println(dna[i]);
            if (space_x + x[dna[i]] >= 0 && space_x + x[dna[i]] < 3 && space_y + y[dna[i]] >= 0 && space_y + y[dna[i]] < 3) {
                int temp = chessBoard[space_y + y[dna[i]]][space_x + x[dna[i]]];
                chessBoard[space_y + y[dna[i]]][space_x + x[dna[i]]] = 0;
                chessBoard[space_y][space_x] = temp;
                space_x += x[dna[i]];
                space_y += y[dna[i]];
//                System.out.println("x="+space_x);
//                System.out.println("y="+space_y);
//                displaychessBoard();
            }
        }
        displaychessBoard();
    }

    void adaption() {
        adaption = 150;
        int flag = 0;
        int length = 0;
        int num = 0;
        for (int i = 0; i < 3; i++) {
            for (int i1 = 0; i1 < 3; i1++) {
                if (chessBoard[i][i1] != num) {
                    flag++;
                    length += manhattan[i * 3 + i1][chessBoard[i][i1]];
                }
                num++;
            }
        }
        adaption = adaption - (flag + length) - right;
        //计算适应度,每个数字的距离原位置的曼哈顿距离加上错位的数字数
//        chessBoard =new int[][] {{7, 2, 4}, {5, 0, 6}, {8, 3, 1}};
    }

    public void displaychessBoard() {
        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 3; j++)
                System.out.print(chessBoard[i][j] + " ");
            System.out.println();
        }
    }
}
测试类
package AI1pulsplus;

import java.util.ArrayList;
import java.util.List;
public class MAIN {
    public static void main(String[] args) {
        long startTime=System.currentTimeMillis();   //获取开始时间
        ChessBoard chessBoard =new ChessBoard();
        long endTime=System.currentTimeMillis(); //获取结束时间
        Runtime s_runtime = Runtime.getRuntime();
        System.out.println("内存:"+(s_runtime.totalMemory() - s_runtime.freeMemory())+"字节" );
        System.out.println("时间:"+(endTime-startTime)+"ms");
//        Individual i =new Individual();
//        char a[] = "3011233223112322130300323001011012001231130101001111011023302132101223023011200103333022200113212222".toCharArray();
//        int b[] = new int[100];
//        for (int q=0;q<100;q++){
//            b[q]=a[q]-'0';
//        }
//        i.dna=b;
//        i.jianyan(100);
//        for(int q=0;q<100;q++)
//            System.out.print(i.dna[q]);
    }
}



  • 3
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 7
    评论
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

rglkt

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值