汉诺塔演示实验(Java代码详解)

一.任务:

设计一个汉诺塔演示软件,自动展示汉诺塔搬运的全过程

二.要求:

(1)实现可视化界面,完成与用户的交互,展示汉诺塔搬运过程。
(2)支持盘子数量自定义设置。
(3)提供开始按钮,点击开始按键,开始展示搬运过程。

(4)提供复位按键,在搬运过程中,点击复位键可以重新回到开始搬运前的状态。

三.问题分析:

  1. 汉诺塔问题求解算法:汉诺塔问题是一个经典的递归问题,涉及递归算法的设计和实现。
  2. 图形用户界面(GUI)设计:使用适当的GUI库和工具进行界面设计,包括窗口、控件(如按钮、输入框等)的布局和样式设置。
  3. 用户交互设计:通过事件处理机制实现用户与软件之间的交互,包括按钮点击事件的捕获和处理。

四.代码:

HanoiWindow类:

package hannuota;

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.JOptionPane;


public class HanoiWindow extends JFrame implements ActionListener {
    //继承JFrame并且实现ActionListener接口
    Tower tower = null;
    int amountOfDisc = 1;
    char[] towerName = { 'A', 'B', 'C' };
    JButton renew = null;
    JButton autoButton = null;


    JPanel center = new JPanel(); //中心面板,放置中心部分
    JTextField discCountField;  //输入盘子数量的文本框

    HanoiWindow() {
        tower = new Tower(towerName);
        tower.setAmountOfDisc(amountOfDisc);//创建tower
        tower.setMaxDiscWidth(120);
        tower.setMinDiscWidth(50);
        tower.setDiscHeight(16);
        tower.putDiscOnTower(); //盘子放在初始位置
        add(tower, BorderLayout.CENTER); //将 Tower 添加到中心位置

        renew = new JButton("复位");
        autoButton = new JButton("开始");


        renew.addActionListener(this);  //添加事件监听器,以便在按钮被点击时触发相应的操作。
        autoButton.addActionListener(this);

        JPanel north = new JPanel();  // 创建北部面板
        JLabel discCountLabel = new JLabel("盘子数量:"); //创建标签
        discCountField = new JTextField(3);
        discCountField.setText(Integer.toString(amountOfDisc));

        north.add(autoButton);
        north.add(renew);
        north.add(discCountLabel); // 在北部面板中添加盘子数量标签
        north.add(discCountField); // 在北部面板中添加文本框

        String mess = "将全部盘子从" + towerName[0] + "座搬运到" +  towerName[2] + "座";
        JLabel hintMess = new JLabel(mess, JLabel.CENTER); // 创建带有指定文本和对齐方式的标签
        north.add(hintMess); // 在北部面板中添加提示信息标签

        add(north, BorderLayout.NORTH); // 在界面上方添加北部面板
        setResizable(false);
        setVisible(true);
        setBounds(60, 60, 460, 410);
        validate(); // 验证此容器及其所有子组件
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // 设置窗口关闭操作
    }
    public void actionPerformed(ActionEvent e) {
        if (e.getSource() == renew) {
            try {
                amountOfDisc = Integer.parseInt(discCountField.getText()); //输入转化为整数
                if (amountOfDisc < 1) {
                    JOptionPane.showMessageDialog(this, "请输入正数", "错误", JOptionPane.ERROR_MESSAGE);
                    discCountField.setText("");
                    return;
                }
                if (amountOfDisc > 10) {
                    JOptionPane.showMessageDialog(this, "输入的数太大,请重新输入", "错误", JOptionPane.ERROR_MESSAGE);
                    discCountField.setText("");
                    return;
                }
                tower.setAmountOfDisc(amountOfDisc);
                tower.putDiscOnTower();
            } catch (NumberFormatException ex) {
                JOptionPane.showMessageDialog(this, "输入有误,请重新输入", "错误", JOptionPane.ERROR_MESSAGE);
            }
        } else if (e.getSource() == autoButton) {
            try {
                amountOfDisc = Integer.parseInt(discCountField.getText());
                if (amountOfDisc < 1) {
                    JOptionPane.showMessageDialog(this, "请输入正数", "错误", JOptionPane.ERROR_MESSAGE);
                    discCountField.setText("");
                    return;
                }
                if (amountOfDisc > 10) {
                    JOptionPane.showMessageDialog(this, "输入的数太大,请重新输入", "错误", JOptionPane.ERROR_MESSAGE);
                    discCountField.setText("");
                    return;
                }
                tower.setAmountOfDisc(amountOfDisc);
                tower.putDiscOnTower();

                int x = this.getBounds().x + this.getBounds().width;
                int y = this.getBounds().y;
                tower.getAutoMoveDisc().setLocation(x, y);
                tower.getAutoMoveDisc().setSize(280, this.getBounds().height);
                tower.getAutoMoveDisc().setVisible(true);
            } catch (NumberFormatException ex) {
                JOptionPane.showMessageDialog(this, "输入有误,请重新输入", "错误", JOptionPane.ERROR_MESSAGE);
                discCountField.setText("");
            }
        }
        validate();
    }



    public static void main(String args[]) {
        new hannuota.HanoiWindow(); //启动界面
    }
}

Tower 类:

package hannuota;
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JPanel;

//用于表示汉诺塔的柱子
// 在Tower类中,通过设置盘子数量、最大盘子宽度、最小盘子宽度和盘子高度等参数来初始化汉诺塔的状态
public class Tower extends JPanel {
    int amountOfDisc = 1;
    hannuota.Disc[] disc; //存储盘子对象。
    int maxDiscWidth, minDiscWidth, discHeight;
    char[] towerName;
    TowerPoint[] pointA;  //声明变量,表示柱子A上的位置
    TowerPoint[] pointB;
    TowerPoint[] pointC;

    AutoMoveDisc autoMoveDisc; //声明移动盘子的变量

    Tower(char[] towerName) {

        this.towerName = towerName;
        setLayout(null); //设置布局管理器为null,即手动控制组件位置
        setBackground(new Color(200, 226, 226));//设置背景颜色
    }

    public void setAmountOfDisc(int number) {
        if (number <= 1)
            amountOfDisc = 1;
        else
            amountOfDisc = number;
    }

    public void setMaxDiscWidth(int m) {

        maxDiscWidth = m;
    }

    public void setMinDiscWidth(int m) {

        minDiscWidth = m;
    }

    public void setDiscHeight(int h) {

        discHeight = h;
    }

    public hannuota.AutoMoveDisc getAutoMoveDisc() {

        return autoMoveDisc;
    }

    public void putDiscOnTower() {  //将盘子放在柱子上
        removeDisk(); //移除之前放置在柱子上的盘子。
        int n = (maxDiscWidth - minDiscWidth) / amountOfDisc; //计算每个盘子的宽度间隔
        disc = new hannuota.Disc[amountOfDisc];  //创建一个长度为amountOfDisc的Disc对象数组。
        for (int i = 0; i < disc.length; i++) {
            disc[i] = new hannuota.Disc();
            disc[i].setNumber(i); //设置盘子的编号。
            int diskwidth = minDiscWidth + i * n;//根据索引计算当前盘子的宽度,下面的disc更宽
            disc[i].setSize(diskwidth, discHeight); //设置盘子的大小
        }
        pointA = new TowerPoint[amountOfDisc]; //创建一个长度为amountOfDisc的TowerPoint对象数组,表示柱子A上的位置。
        pointB = new TowerPoint[amountOfDisc];
        pointC = new TowerPoint[amountOfDisc];
        int vertialDistance = discHeight; //设置垂直距离为盘子的高度
        for (int i = 0; i < pointA.length; i++) {  //遍历柱子A上的位置数组
            pointA[i] = new TowerPoint(maxDiscWidth, 100 + vertialDistance);
            //实例化一个新的TowerPoint对象,表示柱子A上的一个位置,并设置位置的横坐标和纵坐标
            vertialDistance = vertialDistance + discHeight;//更新垂直距离。
        }
        vertialDistance = discHeight;
        for (int i = 0; i < pointB.length; i++) {
            pointB[i] = new TowerPoint(2 * maxDiscWidth, 100 + vertialDistance);
            vertialDistance = vertialDistance + discHeight;
        }
        vertialDistance = discHeight;
        for (int i = 0; i < pointC.length; i++) {
            pointC[i] = new TowerPoint(3 * maxDiscWidth, 100 + vertialDistance);
            vertialDistance = vertialDistance + discHeight;
        }
        for (int i = 0; i < pointA.length; i++) {
            pointA[i].putDisc(disc[i], this);  //遍历柱子A上的位置数组,将盘子放置在柱子A上的一个位置上
        }

       autoMoveDisc = new hannuota.AutoMoveDisc(this); //实例化一个新的AutoMoveDisc对象,并将当前Tower对象传递给构造函数。
        autoMoveDisc.setTowerName(towerName);
        autoMoveDisc.setAmountOfDisc(amountOfDisc);
        autoMoveDisc.setPointA(pointA);
        autoMoveDisc.setPointB(pointB);
        autoMoveDisc.setPointC(pointC);
        validate();
        repaint();  //重绘组件
    }

    public void removeDisk() {   //移除所有柱子上的盘子,通过遍历柱子A、B、C上的位置数组,依次移除每个位置上的盘子
        if (pointA != null) {  //检查柱子A上的位置数组是否为null
            for (int i = 0; i < pointA.length; i++) {  //遍历柱子A上的位置数组
                pointA[i].removeDisc(pointA[i].getDiscOnPoint(), this); //调用柱子A上位置数组中第i个位置的removeDisc方法,将该位置上的盘子移除
                pointB[i].removeDisc(pointB[i].getDiscOnPoint(), this);
                pointC[i].removeDisc(pointC[i].getDiscOnPoint(), this);
            }
        }
    }
    //重写的paintComponent方法,用于在组件上绘制柱子、盘子和文字等内容
    public void paintComponent(Graphics g) {  //用于绘制柱子、盘子和文字等内容
        super.paintComponent(g);
        int x1, y1, x2, y2;
        //计算并绘制柱子A上的线段
        //获取柱子A底部盘子的x、y坐标并调整位置。
        x1 = pointA[0].getX();
        y1 = pointA[0].getY() - discHeight / 2;
        x2 = pointA[amountOfDisc - 1].getX();
        y2 = pointA[amountOfDisc - 1].getY() + discHeight / 2;
        g.drawLine(x1, y1, x2, y2);//划线,绘制从柱子A底部到顶部盘子的线段

        x1 = pointB[0].getX();
        y1 = pointB[0].getY() - discHeight / 2;
        x2 = pointB[amountOfDisc - 1].getX();
        y2 = pointB[amountOfDisc - 1].getY() + discHeight / 2;
        g.drawLine(x1, y1, x2, y2);

        x1 = pointC[0].getX();
        y1 = pointC[0].getY() - discHeight / 2;
        x2 = pointC[amountOfDisc - 1].getX();
        y2 = pointC[amountOfDisc - 1].getY() + discHeight / 2;
        g.drawLine(x1, y1, x2, y2);

        g.setColor(Color.blue);//设置绘图颜色为蓝色

        //计算矩形的位置和大小,并用蓝色填充矩形,用来表示每个柱子的底座
        x1 = pointA[amountOfDisc - 1].getX() - maxDiscWidth / 2;
        y1 = pointA[amountOfDisc - 1].getY() + discHeight / 2;
        x2 = pointC[amountOfDisc - 1].getX() + maxDiscWidth / 2;
        y2 = pointC[amountOfDisc - 1].getY() + discHeight / 2;
        int length = x2 - x1, height = 6;
        g.fillRect(x1, y1, length, height);//填充矩形

        int size = 5; //初始化一个点的大小为5,并遍历柱子A、B、C上的位置数组,绘制代表盘子的圆点
        for (int i = 0; i < pointA.length; i++) {
            //缩短 width和height  画点
            g.fillOval(pointA[i].getX() - size / 2, pointA[i].getY() - size / 2, size, size);
            g.fillOval(pointB[i].getX() - size / 2, pointB[i].getY() - size / 2, size, size);
            g.fillOval(pointC[i].getX() - size / 2, pointC[i].getY() - size / 2, size, size);
        }
        //画字符串,通过g.drawString方法在每个柱子的顶部位置绘制字符串,显示柱子的名称
        g.drawString(towerName[0] + "座", pointA[amountOfDisc - 1].getX(), pointA[amountOfDisc - 1].getY() + 50);
        g.drawString(towerName[1] + "座", pointB[amountOfDisc - 1].getX(), pointB[amountOfDisc - 1].getY() + 50);
        g.drawString(towerName[2] + "座", pointC[amountOfDisc - 1].getX(), pointC[amountOfDisc - 1].getY() + 50);
    }
}

TowerPoint类:

package hannuota;

import java.awt.Component;
import java.awt.Container;
//表示汉诺塔游戏中的塔座位置
public class TowerPoint {
    int x, y; //表示塔座位置的横纵坐标
    boolean haveDisc;  //用于表示该位置是否有盘子
    Disc disc = null; //表示当前位置上的盘子,默认为null。



    public TowerPoint(int x, int y) {  //初始化塔座位置的横纵坐标
        this.x = x;
        this.y = y;
    }

    public boolean isHaveDisc() { //判断该位置是否有盘子
        return haveDisc;
    }

    public void setHaveDisc(boolean boo) { //设置当前位置是否有盘子

        haveDisc = boo;  //将传入的布尔值boo赋给haveDisc表示是否有盘子。


    }

    public int getX() {  //获取塔座位置的横坐标。



        return x;
    }

    public int getY() {  //获取塔座位置的纵坐标

        return y;
    }

    public boolean equals(TowerPoint p) {  //比较两个塔座位置是否相等
        if (p.getX() == this.getX() && p.getY() == this.getY())  //判断传入的塔座位置p的横纵坐标是否与当前实例的横纵坐标相等
            return true;
        else
            return false;
    }

    public void putDisc(Component com, Container con) {  //将盘子放置到该塔座位置上。


        disc = (Disc) com;  //将传入的组件com转换为Disc对象,并赋值给disc表示该位置上的盘子
        con.setLayout(null); //设置容器con的布局为null,即自由布局
        con.add(disc); //将盘子组件添加到容器中
        int w = disc.getBounds().width; //获取盘子组件的宽度和高度。
        int h = disc.getBounds().height; //设置盘子组件在容器中的位置
        disc.setBounds(x - w / 2, y - h / 2, w, h); //设置盘子组件在容器中的位置。
        haveDisc = true; //将该位置的haveDisc属性设置为true表示该位置上有盘子
        disc.setPoint(this); //将该位置信息设置到盘子对象中
        con.validate(); //对容器进行验证,以确保界面的更新
    }

    public Disc getDiscOnPoint() {  //定义了一个方法,用于获取该塔座位置上的盘子对象
        return disc;
    }

    //refresh
    public void removeDisc(Component com, Container con) {   //用于移除该位置上的盘子,com盘子,con塔
        if (com != null)  //检查传入的组件是否为空
            con.remove(com);
        con.validate();
    }
}

 Disc类:

package hannuota;

import java.awt.Color;

import javax.swing.JButton;
//定义了一个表示盘子的类Disc,其中包含了盘子的编号、位置信息以及相关的设置和获取方法
public class Disc extends JButton {
    int number;
    TowerPoint point;

    Disc() {
        setBackground(Color.cyan);
    }

    public void setNumber(int n) {
        number = n;
    }

    public int getNumber() {
        return number;
    }

    public void setPoint(TowerPoint p) {
        point = p;
    }

    public TowerPoint getPoint() {
        return point;
    }
}

AutoMoveDisc:

package hannuota;

import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.Timer;

public class AutoMoveDisc extends JDialog implements ActionListener {  //定义了一个名为"AutoMoveDisc"的类,继承自JDialog类,并实现了ActionListener接口
   //声明了一些变量,用于存储盘子数量、柱子对象、柱子名称、界面容器、移动步骤等信息
    int amountOfDisc = 1;
    TowerPoint[] pointA;
    TowerPoint[] pointB;
    TowerPoint[] pointC;
    char[] towerName;
    Container con;
    StringBuffer moveStep;
    JTextArea showStep;
    JButton bStart, bStop, bContinue, bClose;
    Timer time;
    int i = 0, number = 0;

    //用于初始化界面和一些变量,并设置界面的布局、按钮的事件监听器
    AutoMoveDisc(Container con) {
        setModal(true);
        setTitle("搬运过程详情");
        this.con = con;
        moveStep = new StringBuffer();
        time = new Timer(100, this);
        time.setInitialDelay(10);
        showStep = new JTextArea(10, 12);
        bStart = new JButton("演示");
        bStop = new JButton("暂停");
        bContinue = new JButton("继续");
        bClose = new JButton("关闭");
        bStart.addActionListener(this);
        bStop.addActionListener(this);
        bContinue.addActionListener(this);
        bClose.addActionListener(this);
        JPanel south = new JPanel();
        south.setLayout(new FlowLayout());
        south.add(bStart);
        south.add(bStop);
        south.add(bContinue);
        south.add(bClose);
        add(new JScrollPane(showStep), BorderLayout.CENTER);
        add(south, BorderLayout.SOUTH);
        setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
        towerName = new char[3];
        addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent e) {
                time.stop();
                setVisible(false);
            }
        });
    }

   // 设置柱子对象、柱子名称和盘子数量等属性
    public void setPointA(TowerPoint[] pointA) {
        this.pointA = pointA;
    }

    public void setPointB(TowerPoint[] pointB) {
        this.pointB = pointB;
    }

    public void setPointC(TowerPoint[] pointC) {
        this.pointC = pointC;
    }

    public void setTowerName(char name[]) {
        if (name[0] == name[1] || name[0] == name[2] || name[1] == name[2]) {
            towerName[0] = 'A';
            towerName[1] = 'B';
            towerName[2] = 'C';
        } else
            towerName = name;
    }

    public void setAmountOfDisc(int n) {
        amountOfDisc = n;
    }

    //这是实现ActionListener接口中的方法,用于处理界面上的按钮点击事件。根据不同的按钮,执行相应的操作
    public void actionPerformed(ActionEvent e) {
        if (e.getSource() == time) {
            number++;
            char cStart, cEnd;
            if (i <= moveStep.length() - 2) {
                cStart = moveStep.charAt(i);
                cEnd = moveStep.charAt(i + 1);
                showStep.append("(" + number + ")从" + cStart + "座搬一个盘子到" + cEnd + "座\n");
                autoMoveDisc(cStart, cEnd);
            }
            i = i + 2;
            if (i >= moveStep.length() - 1) {
                time.stop();
            }
        } else if (e.getSource() == bStart) {
            if (moveStep.length() == 0) {
                if (time.isRunning() == false) {
                    i = 0;
                    moveStep = new StringBuffer();
                    setMoveStep(amountOfDisc, towerName[0], towerName[1], towerName[2]);
                    number = 0;
                    time.start();
                }
            }
        } else if (e.getSource() == bStop) {
            if (time.isRunning() == true)
                time.stop();
        } else if (e.getSource() == bContinue) {
            if (time.isRunning() == false)
                time.restart();
        } else if (e.getSource() == bClose) {
            time.stop();
            setVisible(false);
        }
    }

    //key,递归实现汉诺塔问题的算法。根据盘子数量和柱子的顺序,将移动步骤记录在moveStep变量中
    private void setMoveStep(int amountOfDisc, char one, char two, char three) {
        if (amountOfDisc == 1) {
            moveStep.append(one);
            moveStep.append(three);
        } else {
            setMoveStep(amountOfDisc - 1, one, three, two);
            moveStep.append(one);
            moveStep.append(three);
            setMoveStep(amountOfDisc - 1, two, one, three);
        }
    }

    //根据传入的起点和终点柱子的名称,获取对应的柱子对象和盘子对象,并进行移动操作
    private void autoMoveDisc(char cStart, char cEnd) {
        Disc disc = null;
        if (cStart == towerName[0]) {
            for (int i = 0; i < pointA.length; i++) {
                if (pointA[i].isHaveDisc() == true) {
                    disc = pointA[i].getDiscOnPoint();
                    pointA[i].setHaveDisc(false);
                    break;
                }
            }
        }
        if (cStart == towerName[1]) {
            for (int i = 0; i < pointB.length; i++) {
                if (pointB[i].isHaveDisc() == true) {
                    disc = pointB[i].getDiscOnPoint();
                    pointB[i].setHaveDisc(false);
                    break;
                }
            }
        }
        if (cStart == towerName[2]) {
            for (int i = 0; i < pointC.length; i++) {
                if (pointC[i].isHaveDisc() == true) {
                    disc = pointC[i].getDiscOnPoint();
                    pointC[i].setHaveDisc(false);
                    break;
                }
            }
        }
        TowerPoint endPoint = null;
        int i = 0;
        if (cEnd == towerName[0]) {
            for (i = 0; i < pointA.length; i++) {
                if (pointA[i].isHaveDisc() == true) {
                    if (i > 0) {
                        endPoint = pointA[i - 1];
                        break;
                    } else if (i == 0)
                        break;
                }
            }
            if (i == pointA.length)
                endPoint = pointA[pointA.length - 1];
        }
        if (cEnd == towerName[1]) {
            for (i = 0; i < pointB.length; i++) {
                if (pointB[i].isHaveDisc() == true) {
                    if (i > 0) {
                        endPoint = pointB[i - 1];
                        break;
                    } else if (i == 0)
                        break;
                }
            }
            if (i == pointB.length)
                endPoint = pointB[pointB.length - 1];
        }
        if (cEnd == towerName[2]) {
            for (i = 0; i < pointC.length; i++) {
                if (pointC[i].isHaveDisc() == true) {
                    if (i > 0) {
                        endPoint = pointC[i - 1];
                        break;
                    } else if (i == 0)
                        break;
                }
            }
            if (i == pointC.length)
                endPoint = pointC[pointC.length - 1];
        }
        if (endPoint != null && disc != null) {
            endPoint.putDisc(disc, con);
            endPoint.setHaveDisc(true);
        }
    }
}

五.运行结果截图:

l

六.总结分析:

 本次汉诺塔实验要求设计一个可自动化移动的汉诺塔,要求具备可以自定义盘子数量,开始复位等功能,在其基础上我添加了第二个可视化界面,可以更加详细的查看盘子的具体移动过程,代码中可能存在需要优化的部分,希望大佬们改正

  • 10
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
汉诺塔游戏是一款非常受欢迎的益智游戏,其规则简单却寓意深刻,不仅能锻炼思维能力,还有助于培养耐心和毅力。而在实现汉诺塔游戏的过程中,Java语言被广泛应用,下面介绍一下Java实现汉诺塔游戏动画演示代码。 在Java中实现汉诺塔游戏动画演示的关键其实就是利用递归的思想来求解游戏。具体实现步骤如下: 1. 定义汉诺塔游戏的三个棍子,可以使用数组或集合来实现。 2. 定义汉诺塔游戏的起始状态和目标状态,即将初始状态上的所有盘子全部移至目标状态上。 3. 定义一个递归函数,根据汉诺塔游戏规则将所有盘子从起始状态移至目标状态。 4. 在递归过程中,每次移动一个盘子,并画出该过程的动画效果。 Java代码实现如下: public void move(int num, char from, char to, char mid) { if (num == 1) { System.out.println("盘子" + num + "由" + from + "移动到" + to); // 在画布上绘制移动的过程 } else { move(num - 1, from, mid, to); System.out.println("盘子" + num + "由" + from + "移动到" + to); // 在画布上绘制移动的过程 move(num - 1, mid, to, from); } } 以上代码实现了汉诺塔游戏的递归求解过程,并在控制台打印了每次盘子移动的情况。要实现动画效果,可以在移动盘子的部分增加绘图操作,例如使用Java的AWT或JavaFX库来实现。 总之,Java实现汉诺塔游戏动画演示代码并不复杂,只需用递归的方式来求解游戏,加上绘图操作即可。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值