精华内容
下载资源
问答
  • 华容道算法基础版

    千次阅读 2019-03-21 10:43:09
    今天来聊聊华容道算法具体实现方法,华容道算法我会通过链表和红黑树两种方法实现查找算法,程序体现出来的效率差别很大。 本篇文章拿华容横刀立马分析,华容游戏下图所示。游戏原理是每个方块每次只可以移动...

    今天来聊聊华容道算法具体实现方法,华容道算法我会通过链表和红黑树两种方法实现查找算法,程序体现出来的效率差别很大。

    本篇文章拿华容道横刀立马做分析,华容道游戏下图所示。游戏原理是每个方块每次只可以移动一个方格,如何将正方形移除到方块外部。拿到这个需求我们首先需要构建数学模型,该游戏设计到的方块数量较少,走法也比较少,那么可以采取穷举思想计算出最佳走法。

    图 1

     

    当方块每移动一步时,程序应该获取到当前游戏盘面下一步可以执行的路径,如果不考虑去除重复状态,那么程序每个盘面节点数量会成指数增加,这样导致计算量太大。华容道效率出现在比较上,不同的查找策略会导致效率差别在几十倍,几百倍上。

             游戏数学模型如下图所示,程序应该通过一个数据结构保留查找过程中出现的所有状态,本次采用链表。程序每走一步应该获取下一步可走的路径,并且把可走路径呈现的盘面结点保存到链表中,同时应该剔除相同盘面结点。同时每个结点还会有结点指针指向下一个盘面和指向父盘面,保留这个指针的意义在于,当程序找到了方块最终应该有的状态,程序可以通过父指针回溯到最佳捷径路径,然后通过栈先进后出策略完成最终路径寻找。

    图 2

     

    程序思路已经很清楚,如何构造每个盘面结点呢?早期由于计算机内存比较小,华容道算法都采取牺牲性能来换取内存空间,一个盘面采用一个int就可以表示完全。盘面和走法图片来源于网络。

    图 3 盘面表示方法

     

    图 4 程序走法思想

     

    上图是用性能换内存思想,现在电脑的内存都比较大,盘面编码方式也随之改变,本次编码采用最简单的数字编码,整个游戏盘面是5*4=20方格,编码方式如下如图所示。

    图 5

    其实这种编码方式效率比较低,如果2和5对调其实是一种状态,本次实验为了简单,由浅入深分析算法效率。下面开始代码编写环节。盘面结点与初始值状态值如下所示,state二维数组用来存储每个结点的实际值,并且赋值为横刀立马的初始值。

    图 6

     

    判断下一步可以的走法,采取遍历二维数组方式。

    图 7

    每次判断得到新的状态,链接到c这个链表后面,上图的整个循环是获取当前盘面的可走的所有方法,在得到可走的路径时需要判断是否与以前盘面结点重复。如何判断下一步可走,下面只列举正方形的走法。其他的棋子走法请看源代码。正方形走法如下所示。

     

     

    图 8

     

    如何判断重复比较重要的环节,本次同样采用效率最低的遍历去判断重复,重链表头比对到链表尾巴,每个结点状态通过一一比较数组的值来判断当前盘面是否重复,这个编码方式与判断重复是最简单的,但效率是最低的,下篇文章提高效率。

    图 9

    棋子连续走几步解决方案,当前从棋子布局初始状态变化到如下状态,如果按照一步一步走法算,这个路径是两步,如果棋子可以拐弯或者走几步,那么达到现在这个状态最多算一步。本次实验没有优化这个代码,下篇文章会提供优化好的华容道算法。

     

    本次实验结果是,该程序运行花费时间为2~3小时,下篇文章优化效率后时间不到10ms。

     

    源码下载:https://download.csdn.net/download/qq_21792169/11044867

    展开全文
  • 算法

    万次阅读 2018-02-08 00:13:09
    1.算法定义 算法(Algorithm)是指解题方案的准确而完整的描述,是一系列解决问题的清晰指令,算法代表着用系统的方法描述解决问题的策略机制。也就是说,能够对一定规范的输入,在有限时间内获得所要求的输出...

    1.算法定义

    算法(Algorithm)是指解题方案的准确而完整的描述,是一系列解决问题的清晰指令,算法代表着用系统的方法描述解决问题的策略机制。也就是说,能够对一定规范的输入,在有限时间内获得所要求的输出。如果一个算法有缺陷,或不适合于某个问题,执行这个算法将不会解决这个问题。不同的算法可能用不同的时间、空间或效率来完成同样的任务。一个算法的优劣可以用空间复杂度与时间复杂度来衡量。

    一个算法应该具有以下七个重要的特征:
    ①有穷性(Finiteness):算法的有穷性是指算法必须能在执行有限个步骤之后终止;
    ②确切性(Definiteness):算法的每一步骤必须有确切的定义;
    ③输入项(Input):一个算法有0个或多个输入,以刻画运算对象的初始情况,所谓0个输 入是指算法本身定出了初始条件;
    ④输出项(Output):一个算法有一个或多个输出,以反映对输入数据加工后的结果。没 有输出的算法是毫无意义的;
    ⑤可行性(Effectiveness):算法中执行的任何计算步骤都是可以被分解为基本的可执行 的操作步,即每个计算步都可以在有限时间内完成(也称之为有效性);
    ⑥高效性(High efficiency):执行速度快,占用资源少;
    ⑦健壮性(Robustness):对数据响应正确。

    2. 时间复杂度

    计算机科学中,算法的时间复杂度是

    展开全文
  • 夜深人静写算法)- 初等数论入门

    万次阅读 多人点赞 2017-12-28 15:33:22
    初等数论:扩展欧几里得算法,中国剩余定理,欧拉函数,容斥原理,大数判素
    展开全文
  • 大多数据结构课本中,串涉及的内容即串的模式匹配,需要掌握的是朴素算法、KMP算法及next值的求法。...3、应算法需要定义的next值 4、手动写出较短串的next值的方法 5、最难理解的、足足有5行的代码...

    大多数据结构课本中,串涉及的内容即串的模式匹配,需要掌握的是朴素算法、KMP算法及next值的求法。在考研备考中,参考严奶奶的教材,我也是在关于求next值的算法中卡了一下午时间,感觉挺有意思的,把一些思考的结果整理出来,与大家一起探讨。

    本文的逻辑顺序为
    1、最基本的朴素算法
    2、优化的KMP算法
    3、应算法需要定义的next值
    4、手动写出较短串的next值的方法
    5、最难理解的、足足有5行的代码的求next值的算法
    所有铺垫为了最后的第5点,我觉得以这个逻辑下来,由果索因还是相对好理解的,下面写的很通俗,略显不专业…

    一、问题描述

    给定一个主串S及一个模式串P,判断模式串是否为主串的子串;若是,返回匹配的第一个元素的位置(序号从1开始),否则返回0;如S=“abcd”,P=“bcd”,则返回2;S=“abcd”,P=“acb”,返回0。

    二、朴素算法

    最简单的方法及一次遍历S与P。以S=“abcabaaaabaaacac”,P="abaabcac"为例,一张动图模拟朴素算法:

    在这里插入图片描述
    这个算法简单,不多说,附上代码

    #include<stdio.h>
    int Index_1(char s[],int sLen,char p[],int pLen){//s为主串,sLen为主串元素个数,p为模式串,pLen为模式串的个数
        if(sLen<pLen)return 0;
        int i = 1,j = 1;
        while(i<=sLen && j<=pLen){
            if(s[i]==p[j]){i++;j++;}
            else{
                i = i-j+2;
                j = 1;
            }
        }
        if(j>pLen) return i-pLen;
        return 0;
    }
    void main(){
        char s[]={' ','a','b','c','a','b','a','a','a','a','b','a','a','b','c','a','c'};//从序号1开始存
        char p[]={' ','a','b','a','a','b','c','a','c'};
        int sLen = sizeof(s)/sizeof(char)-1;
        int pLen = sizeof(p)/sizeof(char)-1;
        printf("%d",Index_1(s,sLen,p,pLen));
    }
    

    三、改进的算法——KMP算法

    朴素算法理解简单,但两个串都有依次遍历,时间复杂度为O(n*m),效率不高。由此有了KMP算法。
    一般的,在一次匹配中,我们是不知道主串的内容的,而模式串是我们自己定义的。
    朴素算法中,P的第j位失配,默认的把P串后移一位。
    但在前一轮的比较中,我们已经知道了P的前(j-1)位与S中间对应的某(j-1)个元素已经匹配成功了。这就意味着,在一轮的尝试匹配中,我们get到了主串的部分内容,我们能否利用这些内容,让P多移几位(我认为这就是KMP算法最根本的东西),减少遍历的趟数呢?答案是肯定的。再看下面改进后的动图:
    在这里插入图片描述

    这个模拟过程即KMP算法,若没有看明白,继续往下看相应的解释,理解需要把P多移几位,然后回头再看一遍这个图就很明了了。

    相比朴素算法:
    朴素算法: 每次失配,S串的索引i定位的本次尝试匹配的第一个字符的后一个。P串的索引j定位到1;T(n)=O(n*m)
    KMP算法: 每次失配,S串的索引i不动,P串的索引j定位到某个数。T(n)=O(n+m),时间效率明显提高

    而这“定位到某个数”,这个数就是接下来引入的next值。(实际上也就是P往后移多少位,换一种说法罢了:从上图中也可以看出,失配时固定i不变,令S[i]与P[某个数]对齐,实际上是P右移几位的另一种表达,只有为什么这么表达,当然是因为程序好写。)

    开——始——划——重——点!(图对逻辑关系比较好理解,但i和j的关系对后面求next的算法好理解!)

    • 比如,Pj处失配,绿色的是Pj,则我们可以确定P1…Pj-1是与Si…Si+j-2相对应的位置一一相等的
      在这里插入图片描述

    • 假设P1…Pj-1中,P1…Pk-1与Pj-k+1…Pj-1是一一相等的,为了下面说的清楚,我们把这种关系叫做“首尾重合”
      在这里插入图片描述

    • 那么可以推出,P1…Pk-1与Si…Si+j-2
      在这里插入图片描述

    • 显然,接下来要做的就是把模式串右移了,移到哪里就不用多说了:
      在这里插入图片描述

    • 为了表示下一轮比较j定位的地方,我们将其定义为next[j],next[j]就是第j个元素前j-1个元素首尾重合部分个数加一,当然,为了能遍历完整,首尾重合部分的元素个数应取到最多,即next[j]应取尽量大的值,原因挺好理解的,可以想个例子模拟一下,会完美跳过正确结果。在上图中就是绿色元素的next值为蓝色元素的序号。也即,对于字符串P,next[8]=4。如此,再看一下上面的动图是不是清楚了不少。

    • 最后,如果我们知道了一个字符串的next值,那么KMP算法也就很好懂了。相比朴素算法,当发生失配时,i不变,j=next[j]就好啦!接下来就是怎么确定next值了。

    四、手动写出一个串的next值

    我们规定任何一个串,next[1]=0。(不用next[0],与串的所有对应),仍是一张动图搞定问题:
    在这里插入图片描述
    这个扫一眼就能依次写出,会了这个方法,应付个期末考试没问题了。

    通过把next值“看”出来,我们再来分析next值,这就很容易得到超级有名的公式了,这个式子对后面的算法理解很重要!所以先要看懂这个式子,如果上面的内容通下来了,这个应该很容易看懂了:
    在这里插入图片描述

    五、求next的算法

    终于到了最后了~短的串的next值我们可以“看”出来,但长的串就需要借助程序了,具体算法刚接触的时候确实不容易理解,但给我的体验,把上面的内容写完,现在感觉简简单单了…先附上程序再做解释,(终于到了传说中的整整5行代码让我整理了一下午)。

    int GetNext(char ch[],int cLen,int next[]){//cLen为串ch的长度
        next[1] = 0;
        int i = 1,j = 0;
        while(i<=cLen){
            if(j==0||ch[i]==ch[j]) next[++i] = ++j;
            else j = next[j];
        }
    }
    
    • 还是先由一般再推优化:
      直接求next[j+1](至于为什么是j+1,是为了和下面的对应)
      根据之前的分析,next[j+1]的值为pj+1的前j个元素的收尾重合的最大个数加一。即需要满足两个条件,把它的值一步步“检验”出来。一是“个数最多”的,因此要从可能的最大值开始验;二是“首尾重合”,因此要一一对应验是否相等。
      不难理解,next[j+1]的最大值为j,所有我们从next[j+1]=j开始“验证”。有以下优先判断顺序:
      if(P1…Pj-1 == P2…Pj) => next[j+1]=j
      else if(P1…Pj-2 == P3…Pj) =>next[j+1]=j-1
      else if(P1…Pj-3 == P4…Pj) =>next[j+1]=j-2



      else if(P1P2 == Pj-1Pj) => next[j+1]=3
      else if(P1 == Pj-1) => next[j+1]=2
      else if(P1 != Pj-1) => next[j+1]=1

      每次前去尾1个,后掐头1个,直至得到next[j+1]

    • 再进一步想,next值是一个“工具”,我们单独的求next[j+1]是完全没有意义的,就是说要求next就要把所有j的next求出来。所有一般的,我们都是已知前j个元素的next值,求next[j+1],以此递推下去,求完整的next数组
      但是,上面的思考过程还是最根本的。所以问题变为两个:知道前j个元素的next的情况下,
      ①next[j+1]的可能的最大值是多少(即从哪开始验证)
      ②某一步验证失败后,需要“前去尾几个,后掐头几个?”(即本次验证失败后,再验证哪个值)
      看一下的分析:

    1、next[j+1]的最大值为next[j]+1。
    因为:
    假设next[j]=k1,则可以说明P1…Pk1-1=Pj-k1+1…Pj-1,且这是前j个元素最大的首尾重合序列。
    如果Pk1=Pj,那么P1…Pk1-1PK=Pj-k1+1…Pj-1Pj,那么k+1这也是前j+1个元素的最大首尾重合序列,也即next[j+1]的值为k1+1
    2、如果Pk1≠Pj,那么next[j+1]可能的次大值为next[next[j]]+1,以此类推即可高效求出next[j+1]
    这里不好解释,直接看下面的流程分析及图解

    开——始——划——重——点!
    从头走一遍流程
    ①求next[j+1],设值为m
    已知next[j]=k1,则有P1…Pk1-1 = Pj-k1+1…Pj-1
    如果Pk1=Pj,则P1…Pk1-1PK = Pj-k1+1…Pj-1Pj,则next[j+1]=k1+1,否则
    已知next[k1]=k2,则有P1…Pk2-1 = Pk1-k2+1…Pk1-1
    ⑤第二第三步联合得到:
    P1…Pk2-1 = Pk1-k2+1…Pk1-1 = Pj-k1+1…Pk2-k1+j-1 = Pj-k2+1…Pj-1 即四段重合
    ⑥这时候,再判断如果Pk2=Pj,则P1…Pk2-1P~k2 = Pj-k2+1…Pj-1Pj,则next[j+1]=k2+1;否则再取next[k2]=k3…以此类推

    上面几步,耐心看下来,结合那个式子很容易看懂。最后,再加一个图的模拟帮助理解:
    1、要求next[k+1] 其中k+1=17
    在这里插入图片描述
    2、已知next[16]=8,则元素有以下关系:
    在这里插入图片描述
    3、如果P8=P16,则明显next[17]=8+1=9
    4、如果不相等,又若next[8]=4,则有以下关系

    在这里插入图片描述
    又加上2的条件知
    在这里插入图片描述
    主要是为了证明:
    在这里插入图片描述
    5、现在在判断,如果P16=P4则next[17]=4+1=5,否则,在继续递推
    6、若next[4]=2,则有以下关系
    在这里插入图片描述
    7、若P16=P2,则next[17]=2+1=3;否则继续取next[2]=1、next[1]=0;遇到0时还没出结果,则递推结束,此时next[17]=1。最后,再返回看那5行算法,应该很容易明白了!

    展开全文
  • 算法》精华 算法设计部分

    千次阅读 2014-08-09 11:09:32
    算法》精华 算法设计部分 本书作者绉恒明,作者另有一本书《数据结构之弦》,以及《操作系统之哲学原理》都是很好的书这本书可以算得上是深入浅出,文笔很好,作者添加了很多自己的思考本文仅包括算法设计...
  • 算法刷到最后,最后记在脑子里的不是代码,是思路,如果你有思路,那你一定能把代码写出来,你不可能记住所有题的代码,唯一可以记住的是解题思路,所以怎么码代码不是一个问题,怎么解题才是一个问题,建议刷题的...
  • 算法》精华 经典算法部分

    万次阅读 多人点赞 2014-08-09 11:11:43
    算法》精华 经典算法部分 本书作者绉恒明,作者另有一本书《数据结构之弦》,以及《操作系统之哲学原理》都是很好的书这本书可以算得上是深入浅出,文笔很好,作者添加了很多自己的思考本文包括经典算法部分 ...
  • Dijkstra算法(迪杰斯特拉算法

    万次阅读 多人点赞 2019-06-24 18:06:30
    对比算法好坏需要考虑的因素 执行算法所耗费的时间 执行算法所耗费的存储空间 Dijkstra算法(迪杰斯特拉算法) 迪杰斯特拉算法是由荷兰计算机科学家狄克斯特拉于1959年提出的,是从一个顶点到其余各顶点的最短路径...
  • 美团面试的两道算法

    千次阅读 2017-06-28 10:25:41
    美团的两道算法题 前天去美团面试,一面和二面问了各问了一道算法题,博主在这里和大家分享一下。 1.二叉树想必大家都了解,对于只有一个节点的二叉树,只会有一种结构,对于有两个节点的二叉树,那么会有2种...
  • Dijkstra算法原理

    万次阅读 多人点赞 2017-02-19 22:46:13
    Dijkstra算法 1.定义概览 Dijkstra(迪杰斯特拉)算法是典型的单源最短路径算法,用于计算一个节点到其他所有节点的最短路径。主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止。Dijkstra算法是很有代表性...
  • 智能优化算法:麻雀搜索算法-附代码

    万次阅读 多人点赞 2020-09-27 16:34:00
    算法结果3.参考文献4.Matlab代码 摘要:麻雀搜索算法(Sparrow Search Algorithm, SSA)是于2020年提出的。SSA 主要是受麻雀的觅食行为和 反捕食行为的启发而提出的。该算法比较新颖,具有寻优能力强,收敛速度快的...
  • 创新一直是一个令人纠结的话题,研究生毕业设计多数需要算法的创新,而博士生毕业... 通常,我们使用一个算法,这里举个简单的粒子,PSO粒子群优化算法,我们通过仿真,会得到该算法的收敛速度,仿真精度等一些参数...
  • 最优化算法之粒子群算法(PSO)

    万次阅读 多人点赞 2018-08-03 10:26:45
    一、粒子群算法的概念   粒子群优化算法(PSO:Particle swarm optimization) 是一种进化计算技术(evolutionary computation)。源于对鸟群捕食的行为研究。粒子群优化算法的基本思想:是通过群体中个体之间的...
  • 由于我之前一直强调数据结构以及算法学习的重要性,所以就有一些读者经常问我,数据结构与算法应该要学习到哪个程度呢?,说实话,这个问题我不知道要怎么回答你,主要取决于你想学习到哪些程度,不过针对这个问题,...
  • 算法算法评价

    万次阅读 多人点赞 2019-07-05 20:42:11
    一、算法的基本概念 算法是对特定问题求解步骤的一种描述,它是指令的有限序列,其中的每条指令表示一个或多个操作。...3.可行性:一个算法是可行的,即算法中描述的操作都是可以通过已经实现的基本运算执行有...
  • 遗传算法

    万次阅读 多人点赞 2019-04-06 21:41:47
    使用遗传算法求解多峰函数的最大值,是我的一项课程作业,完之后,顺便把文档整理出来个记录。全部内容如下: 1、问题描述 编程实现遗传算法,并求解多峰函数的最大值。多峰函数的表达式如下所示: 用MATLAB...
  • 页面置换算法-CLOCK置换算法及其改进版算法

    万次阅读 多人点赞 2018-12-29 13:31:51
    页面置换算法中的LRU算法最接近理想情况下的OPT算法,但是实现起来比较困难且开销较大,所以很多设计者试图用开销比较小的算法接近LRU算法,CLOCK算法就是其中一种。 1.简单的CLOCK算法是通过给每一个访问的页面...
  • 五大常用算法:贪心算法

    万次阅读 2018-03-14 13:11:26
    贪心算法一、基本概念: 所谓贪心算法是指,在对问题求解时,总是做出在当前看来是最好的选择。也就是说,不从整体最优上加以考虑,他所做出的仅是在某种意义上的局部最优解。 贪心算法没有固定的算法框架,算法...
  • 算法导论(正宗中文第版)3-1

    千次下载 热门讨论 2014-01-11 16:20:34
    在有关算法的书中,有一些叙述非常严谨,但不够全面;另一些涉及了大量的题材,但又缺乏严谨性。本书将严谨性和全面性融为一体,深入讨论各类算法,并着力使... 新增100练习和28思考题,还更新并补充了参考文献。
  • 快速幂算法——带你从零开始一步一步优化 目录 快速幂算法——带你从零开始一步一步优化 ...首先,我们先来看一道ACM程序设计题,这题是杭电OJ中序号为2035的题目,没过这题目的同学可以...
  • C语言常用算法题 (嵌入式算法题) 28

    万次阅读 多人点赞 2018-07-26 08:46:40
    最近准备打牢一点C语言,我会把这些基础的算法粘贴出来,一起,学习交流。   实现加减乘除计算器。 输入两个数并输出最大值,最小值 判断输出,输入0,1,2,3,输出aaaa,bbbbb,cccc,dddd 输入一个大写或者...
  • Dijkstra算法

    万次阅读 2021-02-17 12:18:58
    戴克斯特拉算法(Dijkstra’s algorithm)是由荷兰计算机科学家艾兹赫尔·戴克斯特拉提出。迪科斯彻算法使用了广度优先搜索解决非负权有向图的单源最短路径问题,算法最终得到一个最短路径树。该算法常用于路由算法...
  • Mysql算法内部算法 - 嵌套循环连接算法1.循环连接算法// 循环连接算法分为两种 1.嵌套循环连接算法 2.块嵌套循环连接算法2....假设个表之间的连接 t1,t2以及 t3,那么NLJ算法会这么来执行:// 规则 Ta
  • 抢占式SJF、优先级调度算法1. 非抢占式优先级调度算法2. 抢占式优先级调度算法四、时间片轮转(RR)算法五、多级队列调度 一、先来先服务(FCFS)调度算法 非抢占式调度,选择就绪队列中等待最长时间的进程。 ...
  • 分类算法 -- 决策树ID3算法

    千次阅读 多人点赞 2019-02-17 01:27:43
    决策树算法是非常常用的分类算法,其分类的思路非常清晰,简单易懂。并且它也是一个很基础的算法,集成学习和随机森林算法是以其为基础的。 算法简介 对于决策树算法,其输入是带有标签的数据,输出是一颗决策树。...
  • C语言算法求解最大公约数与最小公倍数

    万次阅读 多人点赞 2017-06-13 22:59:15
    问题:请从键盘上输入两...了解了其含义,接下来就是构思算法,通常而言,求解最大公约数有算法,而最小公倍数的求解,我们可以很容易的推断出,最小公倍数等于两个数值的乘积除以这两个数值的最大公约数。那么接下
  • 数据挖掘算法——常用分类算法总结

    万次阅读 多人点赞 2019-06-17 10:55:22
    常用分类算法总结分类算法总结NBC算法LR算法SVM算法ID3算法C4.5 算法C5.0算法KNN 算法ANN 算法 分类算法总结 分类是在一群已经知道类别标号的样本中,训练一种分类器,让其能够对某种未知的样本进行分类。分类算法...
  • 3DES加密算法原理

    万次阅读 2019-10-07 17:42:46
    3DES,也称为 3DESede 或 TripleDES,是三重数据加密算法,相当于是对每个数据库应用次DES的对称加密算法。 由于DES密码长度容易被暴力破解,所以3DES算法通过对DES算法进行改进,增加DES的密钥长度来避免类似的...
  • 算法攻略

    2020-05-16 12:20:11
    3. 数据结构:系统的讲解了常见的数据结构(栈、队列、链表、树、图) 4. 算法及思想:递归算啊、二分查找、位运算、散列表及哈希算法、字符串匹配算法算法思想(贪心算法、分治算法、回溯算法、动态规划) 5. ...
  • 带你入门多目标跟踪()匈牙利算法&KM算法

    万次阅读 多人点赞 2019-07-02 19:30:41
    匈牙利算法(Hungarian Algorithm)与KM算法(Kuhn-Munkres Algorithm)是多目标跟踪的小伙伴很容易在论文中见到的两种算法。他们都是用来解决多目标跟踪中的数据关联问题。 对理论没有兴趣的小伙伴可以先跳过...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 3,388,511
精华内容 1,355,404
关键字:

做三道算法