离散数学大作业任务书

这篇具有很好参考价值的文章主要介绍了离散数学大作业任务书。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目   录

  • 实际的练习题目、系统的总功能和各子模块的功能………………………………………………………………………………1

1.1题目及问题描述………………………………………………………………1

1.2功能概述………………………………………………………………………1

1.3技术选型………………………………………………………………………1

1.4代码实现………………………………………………………………………2

  • 主要算法简述…………………………………………………………9
  • 程序流程图……………………………………………………………10

3.1功能模块设计…………………………………………………………………10

3.2关键方法流程图………………………………………………………………11

3.3界面设计………………………………………………………………………11

3.4系统测试………………………………………………………………………11

  • 总结报告………………………………………………………………16
  • 实际的练习题目、系统的总功能和各子模块的功能
    1. 题目及问题描述

(1)求任意一个命题公式的真值表。

(2)利用真值表求任意一个命题公式的主范式。

(3)判断两个命题公式是否等值。

    1. 功能概述

1. 求任意一个命题公式的真值表:首先通过调用init函数输入命题公式,然后根据命题公式中包含的所有变量,生成该命题公式的真值表,即计算所有可能情况下命题公式的结果,并输出其真值表。

2. 利用真值表求任意一个命题公式的主范式:根据真值表中为1或0的情况,计算得出该命题公式的主合取范式和主析取范式,并分别输出。

3. 判断两个命题公式是否等值:输入两个命题公式,分别计算它们的真值表,并比较它们的真值表是否相等,最后输出结果。

    1. 技术选型

操作系统

Windows 11

编程语言(及版本)

C++

编辑软件/IDE

VS

    1. 代码实现
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<string>
#include<map>
#include<vector>
#include<queue>
#include<algorithm>
using namespace std;

typedef struct optrstack
{
    char oper[30];
    int loc;
}OPStack;
void initop(OPStack& op)
{
    int  i;
    op.loc = 0;
    for (i = 0; i < 30; i++)op.oper[i] = '\0';
}
void push(OPStack& op, char c)
{
    op.oper[op.loc++] = c;
}
char pop(OPStack& op)
{
    return(op.oper[--op.loc]);
}
typedef struct opndstack
{
    int oper[60];
    int loc;
}OPndStack;
void initopnd(OPndStack& op)
{
    int  i;
    op.loc = 0;
    for (i = 0; i < 30; i++)op.oper[i] = '\0';
}
void pushopnd(OPndStack& op, int c)
{
    op.oper[op.loc++] = c;
}
int popopnd(OPndStack& op)
{
    return(op.oper[--op.loc]);
}
void init(char s[])
{
    int t;
    printf("\n请输入任意一个命题公式(命题变元为一个字符)\n");
    printf("非、析取、合取、条件、双条件词分别用符号!、|、&、-、+表示\n");
    cin>>s;
    t = strlen(s);
    s[t] = '@';
    s[t + 1] = '\0';
}
int is_optr(char c)
{
    char optr_list[] = "+-|&!()@";
    for (int i = 0; i < (int)strlen(optr_list); i++) if (c == optr_list[i])return 1;
    return 0;
}
char first(char op1, char op2)
{
    char tab[8][9] = {
          "><<<<<>>",
    ">><<<<>>",
    ">>><<<>>",
    ">>>><<>>",
    ">>>>><>>",
    "<<<<<<=E",
    ">>>>>E>>",
    "<<<<<<E=",
    };
    char optr_list[] = "+-|&!()@";//双条件、条件、析取、合取、非
    int op1_loc, op2_loc;
    for (op1_loc = 0; op1_loc < (int)strlen(optr_list); op1_loc++)if (optr_list[op1_loc] == op1)break;
    for (op2_loc = 0; op2_loc < (int)strlen(optr_list); op2_loc++)if (optr_list[op2_loc] == op2)break;
    return tab[op1_loc][op2_loc];
}
int operate(int x, char op, int y)
{
    switch (op) {
    case '+': return (((!x) || y) && (x || (!y))); break;
    case '-': return ((!x) || y); break;
    case '|': return x || y; break;
    case '&': return x && y; break;
    }
    return -1;
}
void divi(char s[], char c[])
{
    int i, j = 0, t;
    for (i = 0; s[i] != '@'; i++) if (!is_optr(s[i])) { for (t = 0; t < j; t++) if (c[t] == s[i]) break;  if (t == j)c[j++] = s[i]; }
    c[j] = '\0';
    char aa;
    for (i = 0; i < j - 1; i++)//按字典序排序
        for (t = i + 1; t < j; t++) if (c[i] > c[t]) { aa = c[i]; c[i] = c[t]; c[t] = aa; }
}
int locate(char s[], char c)
{
    int i;
    for (i = 0; i < (int)strlen(s); i++) if (s[i] == c)break;
    return i;
}
int calc(char s[100], int* p)
{
    char myopnd[10], c;
    int sloc = 0;
    OPStack optr;
    initop(optr);
    push(optr, '@');
    OPndStack  opnd;
    initopnd(opnd);
    divi(s, myopnd);
    c = s[sloc++];
    while (c != '@' || optr.oper[optr.loc - 1] != '@') {
        if (!is_optr(c)) { int d1;  d1 = p[locate(myopnd, c)];  pushopnd(opnd, d1);  c = s[sloc++]; }
        else {
            switch (first(optr.oper[optr.loc - 1], c)) {
            case '<': push(optr, c);  c = s[sloc++];  break;
            case '=': pop(optr);  c = s[sloc++];  break;
            case '>': char op;  op = pop(optr);
                if (op == '!') { int a;  a = !popopnd(opnd);  pushopnd(opnd, a); }
                else {
                    int a, b;  a = popopnd(opnd);  b = popopnd(opnd);
                    int res;  res = operate(b, op, a);  pushopnd(opnd, res);
                }
                break;
            }
        }
    }
    return opnd.oper[opnd.loc - 1];
}
void main()
{
    //(1)求任意一个命题公式的真值表:
    cout << "求任意一个命题公式的真值表:" << endl;
    char exp[100], myopnd[10];
    int i, j, n, m, A[1024][10], flag, k;
    int F[1024];
    init(exp);
    divi(exp, myopnd);
    n = (int)strlen(myopnd);
    m = (int)pow(2, n);
    for (j = 0; j < n; j++) {
        flag = 1;
        k = (int)pow(2, n - j - 1);
        for (i = 0; i < m; i++) {
            if (!(i % k))flag = !flag;
            if (flag)A[i][j] = 1;
            else  A[i][j] = 0;
        }
    }
    char ss[100];
    int t;
    strcpy(ss, exp);
    t = (int)strlen(ss);
    ss[t - 1] = '\0';
    printf("命题公式%s的真值表如下:\n", ss);
    for (j = 0; j < n; j++)printf("%4c", myopnd[j]);
    printf("   %s\n", ss);
    for (i = 0; i < m; i++) {
        for (j = 0; j < n; j++)printf("%4d", A[i][j]);
        F[i] = calc(exp, A[i]);
        printf("%6d", F[i]);
        printf("\n");
    }
  //  (2)利用真值表求任意一个命题公式的主范式。
    // 计算主合取范式
    printf("\n命题公式%s的主合取范式为:\n", ss);
    for (i = 0; i < m; i++) {
        if (F[i] == 0) continue;
        printf("(");
        for (j = 0; j < n; j++) {
            if (A[i][j] == 0) printf("%c", myopnd[j]);
            else printf("!%c", myopnd[j]);
            if (j != n - 1 && A[i + 1][j + 1] == 1) printf("&");
        }
        printf(")");
        if (i != m - 1 && F[i + 1]) printf("|");
    }

    // 计算主析取范式
    printf("\n命题公式%s的主析取范式为:\n", ss);
    for (i = 0; i < m; i++) {
        if (F[i] == 1) continue;
        printf("(");
        for (j = 0; j < n; j++) {
            if (A[i][j] == 1) printf("%c", myopnd[j]);
            else printf("!%c", myopnd[j]);
            if (j != n - 1 && A[i + 1][j + 1] == 1) printf("|");
        }
        printf(")");
        if (i != m - 1 && F[i + 1] == 0) printf("&");
    }
    cout << endl;


    //(3)判断两个命题公式是否等值。
    // 计算第一个命题公式的真值表
    //前面已经输入过第一个命题公式,其数据直接用就行
    cout << "请再输入一个命题公式,判断两个命题公式是否等值:" << endl;
     int F1[1024], F2[1024];
    divi(exp, myopnd);
    n = (int)strlen(myopnd);
    m = (int)pow(2, n);
    for (j = 0; j < n; j++)
for (i = 0; i < m; i++) {
        for (j = 0; j < n; j++)
        F1[i] = calc(exp, A[i]);
     
    }

    // 计算第二个命题公式的真值表
    char exp2[100], myopnd2[10];
    init(exp2);//插入新的命题公式,并计算其真值表
    divi(exp2, myopnd2);

    printf("第二个命题公式%s的真值表如下:\n", exp2);
    for (j = 0; j < n; j++)printf("%4c", myopnd2[j]);
    printf("   %s\n", exp2);
    for (i = 0; i < m; i++) {
        for (j = 0; j < n; j++)printf("%4d", A[i][j]);
        F2[i] = calc(exp2, A[i]);
        printf("%6d", F2[i]);
        printf("\n");
      
    }
  printf("\n");
    // 判断两个命题公式是否等值
    int equal = 1;
    for (i = 0; i < m; i++) {
        if (F1[i] != F2[i]) {
            equal = 0;
            break;
        }
    }
    if (equal) printf("****两个命题公式相等\n");
    else printf("****两个命题公式不相等\n");

   
}


  • 主要算法简述

这份代码实现的是命题逻辑中的真值表,主合取范式、主析取范式和判断两个命题公式是否等值的功能。

在计算命题公式的真值表时,程序先输入命题公式,然后将每一个命题变元的可能取值全部遍历一遍,最后通过逐行计算得到整个真值表。在计算主合取范式和主析取范式时,程序会扫描整个真值表,并将所有取值为1或0的行(具体要看是求主合取范式还是主析取范式)转换为对应的逻辑表达式。

至于判断两个命题公式是否等值,则是先计算出两个真值表,再逐行进行比较。

整个程序用到的数据结构主要是栈,用于控制运算符优先级以及存储操作数。由于命题逻辑的运算符并不多,所以代码里使用了一个二维数组来存储两个运算符之间的优先级关系,从而避免了繁琐的if-else语句。

需要注意的是,这份代码实现的是命题逻辑,而不是一阶逻辑。如果要实现更高阶别的逻辑,需要修改部分代码和数据结构。

  • 程序流程图
    1. 离散数学大作业任务书功能模块设计
  • 基础功能
  • 读取命题公式:从用户处获取输入的命题公式。
  • 解析命题公式:将中缀表达式转换为后缀表达式,并建立一个命题变元编号与变量名的对应关系,可以利用栈来实现。
  • 生成真值表:根据命题变元的个数生成真值表的表头,并依次遍历每一行,在当前行计算出命题公式的取值结果,并将结果填充至真值表中。
  • 计算主合取范式和主析取范式:扫描整张真值表,找出所有取值为1或0的行(具体要看是求主合取范式还是主析取范式),并将它们转换为对应的逻辑表达式。这部分可以使用字符串拼接来实现。
  • 判断两个命题公式是否等价:分别计算出两个命题公式的真值表,然后逐行比较它们的取值是否相同。
  • 输出结果:将命题公式的真值表、主合取范式、主析取范式和是否等价的结果输出给用户。
    1. 关键方法流程图
  • 生成真值表
  • 计算主合取范式和主析取范式
  • 判断两个命题公式是否等价
  • 总结报告
  1. 大作业完成中遇到的主要问题和解决方法

在完成命题逻辑代码的过程中,可能会遇到以下一些问题:

1- 在解析命题公式时,可能会遇到表达式中带有多个括号的情况。这时可以使用栈来处理,每当遇到左括号时就将其入栈,在遇到右括号时就将栈顶的左括号出栈,并将中间的表达式加入后缀表达式中,即将不同运算符设定不同的优先级,从而确定括号的结合顺序。为了简化这个问题,我们可以采用逆波兰式表示法,将操作数放在前面,运算符放在后面的形式来表示算式。这样就不需要考虑括号在算式中的位置了。

2- 在生成真值表时,可能会遇到变量名长度不同、包含空格或其他特殊字符等问题。为了解决这些问题,可以使用哈希表来存储变量名和变元编号之间的对应关系。

3- 在计算主合取范式和主析取范式时,可以采用字符串拼接的方式来组合起真值表中取值为1或0的行所对应的逻辑表达式。

4-处理非操作符(~)和双重否定:在处理命题公式的过程中,我遇到非操作符和双重否定的情况。为了对这些情况进行处理,可以使用递归的方式来实现。具体来说,在从左到右解析命题公式的过程中,如果遇到非操作符(~),则将后面的命题公式作为参数递归调用自身,再添加一个“~”操作符,作为新的一项存入栈中;如果遇到双重否定,则直接跳过两个“~”操作符并继续解析后面的命题公式。

5-处理表达式中的变量名:有时在命题公式中会包含变量名,需要对这些变量名进行处理才能计算出表达式的值。一个简单的方法是将变量名转换为布尔型变量,例如,将“P”和“Q”转换为True和False。但是,如果变量名比较多或者变量名的长度不同,这种方法就会变得复杂和低效。为了解决这个问题,我们可以使用哈希表(Hash Table)来存储变量名和对应的布尔型变量之间的映射关系。具体来说,我们可以将变量名所对应的布尔值存储在哈希表中,然后在解析命题公式时,可以直接查找哈希表中的值并进行替换。

6-处理表达式中的逻辑运算符:在逻辑运算的时候,我不知如何明确表示逻辑运算符。命题公式中常见的逻辑运算符包括“与(&)”、“或(|)”、“非(~)”、“蕴含(->)”和“等价(<->)”。为了正确处理这些运算符,我们需要考虑它们的优先级和结合性。一般来说,非运算符的优先级最高,其次是与运算和或运算,蕴含和等价运算的优先级相同,但比与运算和或运算低。而这些运算符的结合性都是从左到右。因此,在解析命题公式时,我们需要将运算符按照优先级和结合性进行合理地组合。

(2)创新和得意之处

1. 使用后缀表达式处理命题公式:后缀表达式是一种不需要括号的表达方式,可以减少符号优先级和括号的复杂性,简化了计算过程。通过这种方式,我们可以使用栈来计算命题的真值。

为了将中缀表达式(常见的算术表达式形式)转换为后缀表达式,我们可以使用运算符栈和输出队列。我们遍历中缀表达式的每个字符,根据其类型进行处理:

*如果是变量名,则直接将其添加到输出队列中。

*如果是操作符,并且运算符栈为空或者运算符栈的栈顶元素为左括号,则将该操作符入栈。

*如果是右括号,则将运算符栈中的操作符依次出栈并放入输出队列中,直到遇到左括号为止。左括号不会进入输出队列,也不会入栈。

*如果是其他操作符(如非、合取、析取等),则将运算符栈中的操作符依次出栈并放入输出队列中,直到栈顶的运算符优先级低于当前操作符或者栈为空,然后将当前操作符入栈。

遍历完中缀表达式后,将运算符栈中剩下的操作符依次出栈并放入输出队列中。最终,输出队列中的元素就是后缀表达式。

2. 使用哈希表存储变量名和变元编号的对应关系:为了方便查找和处理变量,我们可以使用哈希表来存储变量名和变元编号的对应关系,实现快速查找的功能。这样,在计算命题公式的过程中,可以直接通过变量名来获取对应的变元编号,而不需要进行线性搜索。

在构建变量表时,我们可以遍历变量列表,为每个变量分配一个唯一的变元编号,并将变量名和变元编号的对应关系存储在哈希表中。这样,当需要获取某个变量对应的变元编号时,我们可以直接通过哈希表查询,而不需要遍历整个变量表。

3. 使用字符串拼接生成主合取范式和主析取范式:通过字符串拼接的方式,我们可以将逻辑表达式转换成主合取范式和主析取范式,减少对逻辑运算符的依赖。通过遍历逻辑表达式的树形结构,并根据逻辑运算符的类型进行递归处理,可以将逻辑表达式转换成与或非的形式。

在生成主合取范式时,我们可以通过遍历逻辑表达式的树形结构,当遇到与运算时,在拼接主合取范式时,将左右子树的主合取范式用"∧"连接起来。对于其他运算符,我们需要进一步考虑它们的组合规则。

类似地,在生成主析取范式时,我们可以通过遍历逻辑表达式的树形结构,当遇到或运算时,在拼接主析取范式时,将左右子树的主析取范式用"∨"连接起来。

(3)大作业完成中存在的不足,需进一步改进的设想

1. 对于复杂命题公式的处理:目前的代码可能会出现栈溢出等问题。我们可以考虑使用递归来解决这个问题,通过递归调用函数来处理复杂的子表达式。可以针对每个逻辑运算符定义一个递归函数,在计算过程中不断分解问题为更小的子问题进行求解。

在处理复杂的子表达式时,我们可以将其解析为子树,并递归地应用相应的处理函数来计算子树的值。这样可以避免栈溢出的问题。

2. 处理重复变量名的问题:如果命题公式中出现重复的变量名,目前的代码可能会出现错误。我们可以考虑在哈希表中加入变量名的出现次数来进行判断,并采取相应的处理措施。例如,在构建变量表时,可以检查变量名是否已经存在,并对重复的变量名进行编号。

当遇到重复的变量名时,我们可以为它们添加不同的后缀或编号以区分它们。例如,在哈希表中存储变量名和变元编号的对应关系时,我们可以为重复变量名添加"_1"、"_2"等后缀,确保每个变量名都是唯一的。

3. 提高计算效率:在计算主合取范式和主析取范式时,目前的代码使用了字符串拼接的方式。但是,在处理复杂的公式时,这种方式的效率可能会较低。我们可以考虑使用二叉树的方式存储逻辑表达式,并利用树的遍历方式将其转换成主合取范式和主析取范式。这样,可以通过遍历二叉树的方式来生成相应的范式,减少了对字符串操作的依赖。

我们可以定义一个二叉树的节点类,包括节点值和左右子节点。通过构建逻辑表达式的二叉树,我们可以利用不同的遍历方式(如前序、中序、后序遍历)来生成主合取范式和主析取范式。遍历过程中,可以根据节点值的类型进行相应的处理,并将结果拼接成范式形式。

这些改进设想可以提高代码的可扩展性、可读性和效率,并使其能够更好地处理复杂的命题公式。

(4)大作业完成中的感想和心得体会

完成这个大作业的过程让我深刻体会到了编程中的创新和挑战。通过思考、调试和优化,我不仅学会了如何设计和实现一个小型的逻辑计算器,还提升了对算法和数据结构的理解和应用能力。同时,也意识到自己在实现过程中存在的不足,并希望在今后的学习和工作中能够不断改进和优化自己的编程技能,为社会、为人类创造更多的价值。

通过这个项目,我深入了解了命题逻辑的背后原理,并将其转化为实际的代码实现,这为我打下了坚实的计算机科学基础。我相信这个项目经历将对我的未来学习和职业发展产生积极的影响,并且培养了我解决问题、思考抽象概念和设计复杂系统的能力。我将继续努力学习,提升我的编程能力!文章来源地址https://www.toymoban.com/news/detail-499363.html

到了这里,关于离散数学大作业任务书的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

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

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

相关文章

  • 基于微信小程序的毕业设计题目(5)php点餐外卖小程序(含开题报告、任务书、中期报告、答辩PPT、论文模板)

    基于微信小程序的毕业设计题目(5)php点菜外卖小程序(含开题报告、任务书、中期报告、答辩PPT、论文模板) 目的 :本课题主要目标是设计并能够实现一个基于微信小程序外卖点菜系统,前台用户使用小程序,后台管理使用基PHP+MySql的B/S架构;通过后台添加菜品,用户通过小程

    2024年02月09日
    浏览(39)
  • 基于微信小程序的毕业设计题目(12)php在线教育视频点播学习小程序(含开题报告、任务书、中期报告、答辩PPT、论文模板)

    基于微信小程序的毕业设计题目(12)php在线教育视频点播学习小程序(含开题报告、任务书、中期报告、答辩PPT、论文模板) 目的 :本课题主要目标是设计并能够实现一个基于微信小程序视频点播系统,前台用户使用小程序,后台管理使用基PHP+MySql的B/S架构;通过后台添加课

    2024年02月08日
    浏览(57)
  • 离散数学题目收集整理练习(期末过关进度50%)

    ✨ 博主: 命运之光 🦄 专栏: 离散数学考前复习(知识点+题) 🍓 专栏: 概率论期末速成(一套卷) 🐳 专栏: 数字电路考前复习 ✨ 博主的其他文章: 点击进入博主的主页​​​​​ 前言: 身为大学生考前复习一定十分痛苦,你有没有过以下这些经历: 1.啊明天要考

    2024年02月09日
    浏览(62)
  • GJB 软件研制任务书-编制规范

    1.1标识 〔要求〕本条应描述本文档所适用的系统、接口实体和接口的完整标识。适用时,应描述其标识号、名称、缩略名、版本号和发布号。 〔解释〕本节要写出:   a)本文档标识号(由配置管理员给定),包括版本号;   b)本文档的标题(即封面的名称);   

    2024年02月14日
    浏览(36)
  • python简易贪吃蛇小游戏任务书含代码

     目  录 第一章 绪论 1.1 开发的背景 1.2 开发的目的 1.3 开发的意义 1.4 开发工具简介 第二章 需求分析 (1) 利用方向键来改变蛇的运行方向。 (2) 在随机的地方产生食物。 (3) 吃到食物就变成新的蛇体,碰到壁或自身则游戏结束,否则正常运行。 第三章 系统概要设计 3.1 设计目

    2024年02月16日
    浏览(37)
  • 校园定位系统app的设计与实现(源码+文档+报告+任务书)

    本系统以HTML、CSS、JavaScript作为开发语言。采用前后端分离思想,开发工具为hubuliderx和uniapp,编程语言为JavaScript、vue3。服务器端通过Node.js开发,以本地服务器为基础,把数据库放入本地服务器,使用预留的接口地址,增加,删除,修改,查找数据库数据。系统基于B/S和And

    2024年02月11日
    浏览(53)
  • 2023年中职组“网络安全”赛项南昌市竞赛任务书

    2023 年中职组“网络安全”赛项 南昌市竞赛任务书 网络空间安全赛项规程 赛项名称:网络空间安全 赛项组别:中职组 通过竞赛,检验参赛选手对网络、服务器系统等网络空间中各个信息系统的安全防护能力,以及分析、处理现场问题的能力。通过本赛项的训练和比赛,培养

    2024年02月08日
    浏览(45)
  • 2023第七届金砖大赛之企业信息系统安全预赛任务书

    目录 任务一:iptables防护 任务二:FTP流量分析 任务三:Web2服务器:Find MSG        攻击机场景:Kali2018 Kali2021        靶机场景:System0002 描述:A集团欲上线一批网络应用服务器,为保障网络应用服务器的安全稳定运行,在服务器上线前需要根据业务需求,对网络应用服

    2024年02月08日
    浏览(42)
  • 2023年贵州省职业技能大赛“网络安全” 项目比赛任务书

    A-1:登录安全加固(Windows, Linux) A-1任务一 登录安全加固(Windows, Linux) 请对服务器Windows、Linux按要求进行相应的设置,提高服务器的安全性。 1.密码策略(Windows, Linux) a.最小密码长度不少于13个字符; b.密码必须符合复杂性要求。 2.用户安全管理(Windows) a.设置取得文件或

    2023年04月23日
    浏览(47)
  • 2023年宜昌市中职组“网络安全”赛项竞赛任务书-2

    202 3 年 宜昌市 中职 组 “网络安全”赛项 竞赛任务书- 2 总计:180分钟 竞赛阶段 任务阶段 竞赛任务 竞赛时间 分值 第一阶段单兵模式系统渗透测试 任务一 Windows操作系统渗透测试 100分钟 700分 任务二 Linux操作系统渗透测试 任务三 数据包分析 任务四 隐藏信息探索 任务五 网

    2024年02月04日
    浏览(40)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包