参赛队名:武长区 枪林弹雨
2017年4月26日,一波三折的复赛终于结束了,我们队最终没能进入决赛。虽然在意料之中,不过还是有些小失望。已经为这个比赛忙了一个月,突然之间不知道干什么好了,干脆写一写自己这次参加比赛的过程吧,算是对自己这一个月工作的总结。

这并不是一篇高级技术文,只是一个原先连Dijkstra都写得艰难的人在比赛中挣扎着一点一点取得微小进步的故事。

报名参赛

最开始看这道题应该是校园宣讲会那天,3月9号,不过那天也就是想想而已,因为看懂题目就花了我好多脑细胞。当时看到比赛的丰厚奖励,不禁怦然心动。不过,最让我心动的还是实习offer,毕竟对我这个非计算机专业而且没有什么项目经历的人来说,通过实习生面试的几率相当渺茫。那天之后也只是加了比赛群,并没有报名,因为当时还有自己的课题要做。那段时间,天天看着比赛群里的大佬讨论题目,看到自己觉得有用的讨论就截图,准备自己忙完手头的事情之后仔细看。

3月19号那天,终于把自己课题的阶段性成果发给导师,然后上官网注册报名,准备全身心投入比赛中。取队名的时候想了半天也没想到什么好名字,手边正好有一本华为的书,是之前参加学校的华为师兄师姐分享会的时候拿到的,叫枪林弹雨中成长,干脆就把队名取成了枪林弹雨。或许可以把这次比赛的赛场比作高手如云的战场,我希望自己在大佬们的枪林弹雨中收获成长。

正式初赛之前(3月19日-3月31日)

刚刚看完题目的时候真是一点思路都没有,就是自己在纸上瞎写瞎画,完全不知道如何入手。我一开始的想法是既然服务器位置不确定,消费节点位置确定,那么能不能从消费节点出发考虑,看一看从消费节点出发的路线在各点上的交叉情况,以次来确定服务器的位置,但是想了很久觉得根本行不通,即使不考虑效率的问题,消费节点之间也会相互干扰。

于是还是觉得应该先把服务器的位置定了,那么怎样选择初始服务器的位置呢?好的服务器指数应该离某些消费节点的距离比较近(cost小),那么我就先求一下所有点到所有消费节点的距离。然后怎么分析?显然不能求到所有消费节点的平均值,因为一个服务器不必距离所有消费节点都很近,那么就只看最小的一个或者最小的几个?我用Dijkstra算法写了一下,找了几个按照上述准则距离消费节点较近的节点,然后和最优解比较了一下,发现基本对不上QAQ 于是暂时放弃了这一思路。而且由于程序写的渣,我当时的速度也是比较慢,感觉浪费时间去找一个不怎么样的初始解,完全不值得。

断了思路的我就开始逛论坛,看知乎上大佬的评论,有人提到说最小费用最大流。我当时感觉没想明白为什么,这明明是一个最小费用流啊,为什么是最小费用最大流?搜了搜最小费用流算法,感觉都不适用啊,没法处理消费节点之间相互竞争的问题。可能大佬们在这里完全不会有我这样的困惑,但对一个没有接触过费用流问题,完全不懂残余网络,只听说过Dijkstra算法的人来说,一切都如此艰难。

转折点大概发生在netcan在知乎上发言那天吧(2017华为软件精英挑战赛参赛心得),看了他的发言,我突然对自己充满了信心,觉得自己应该也能做好。在他的知乎回复之下的讨论里,我看到有人也有和我一样的困惑——连续费用路会造成消费节点的相互竞争,不过netcan本人回答说不会。看了之后我想自己先写写看吧,于是用Dijkstra写了一个连续最短费用路(这是一个错误的思路,错误一在于我把用掉的费用路直接拿掉了,没加负权边,错误二在于我没加超级汇点,消费节点是一个一个算的,这样的话它们之间必然相互干扰)。写完之后我就拿netcan发的最优服务器位置来验证正确性,测前两个case的时候居然和他的费用一样,我一度很开心,不过后面几个就比他的高了。检查了半天发现代码没有错误之后,我终于还是意识到自己理解的费用流有误。

再度陷入僵局,我又开始在网上搜最小费用流的资料。很偶然,我看到了节点存在容量限制时的处理方案——化点为边,这种化归的思想让我瞬间我就明白了为何netcan说不存在消费节点的竞争问题。只要加一个超级汇点,把超级汇点和各消费节点相连,然后把消费节点的带宽需求化归为链路容量,这不就变成一个单汇点的费用流问题了吗?而且我也很快明白了为什么大家都说这是一个最小费用最大流问题,因为做了上述处理之后,全图的最小割一定不会超过所有消费节点的需求之和,满足消费节点需求的可行流必定也是最大流。随后我把最小费用最大流算法又认真看了一遍(因为之前没有想到上述的化归方式,所以没认真看残余网络之类的东西),这次才是真正理解了残余网络,理解了为什么要加负权边。

然而,这个问题和多数网上的教程还有一点不同,那就是链路是双向的,几乎所有教程都是拿单向图做例子的。如果是单向图,两点之间有一条正权边,一条负权边;但如果是双向图,那就是4条边了。如果用邻接表存图的话,这个问题实际上不是问题,但我当时对邻接表不熟,所以我是用邻接矩阵存图的,一个矩阵最多存2条边,怎么能同时处理4条边呢?(后来复赛期间我才意识到两点之间的上行和下行链路是不可能同时存在流量的,否则就不可能是最小费用流,所以下面我做了很多后来看来完全没有必要的工作)于是我用了2个矩阵来存图,一个存小编号->大编号,另一个存大编号->小编号。不仅如此,在记录费用路的时候,我也费劲心机区分了到底是上行路还是下行路,具体方法就不说了,因为这些是完全没必要的. 关于最终的费用路输出问题,我倒是没有犯很多人犯的错误——直接输出增广路径,在我顿悟的那天我就理解了残余网络的含义,所以我知道直接输出增广路很可能会超流 ,必须记录每条链路最终的流量状态,然后再从中一条一条地把路径剥离出来。

之前最短路径只懂Dijkstra,不过残余网络存在负权边,不能直接使用Dijkstra,所以我就选了SPFA来找最短路,这个算法实现起来比Dijkstra还要简单,不到一天的时间,我就把整图费用流写了出来,于是我又开始拿netcan给的case做测试。测了5个case,有一个case的费用比他给出的高,我猜一定是程序里面有bug,然而找了一个晚上无果。那天睡觉的时候,我都一直在想到底是哪里出了问题。如果代码没有错误,有没有可能是我做的一些特殊处理出了问题,比如双矩阵存储,上下行链路区分,但是想破脑袋也还是没有发现错误。第二天,我发现netcan把自己在知乎的回答转到了博客上,而且博客里面给出了具体的链路输出。我看了一个有问题那个case的最终输出路径,发现他在知乎上少给了一个服务器,所以我算出的费用总是比他高。加上那个服务器后,答案就对上了。虽说困扰了我一个晚上,不过在这一晚上的思考中,我倒也对这个问题加深了很多认识,认真考虑了很多之前没有细想的问题,也算值了。

到此,费用流部分就完成了,接下来要开始写启发式算法了。时间已经来到了3月27号,当时是说4月1日初赛正式开始之后会限制提交次数,所以我很着急,想赶在1号之前写出一个可以提交的程序。并没有想太多,我就确定了一个初步方案。1.初始服务器全部直连消费节点。2.删点法:对每台服务器的输出流量进行排序,输出流量越小说明效能越低,所以从最小的开始尝试删除,如果费用减小就接受并更新服务器流量排序表,利用新表继续尝试删点;否则在原表中找到下一台服务器尝试删除。3.换点法:同样是依据2的排序来的,不过这里删除服务器后会在与改点相连的点上增添一台新服务器,同样是费用减小时才接受。4.2和3是交替进行的,当2和3都无法找到更小费用的方案时,循环终止输出方案。具体的设计我试了很多,这里不详述了。

相比费用流,上面的算法好写多了,虽然中间有一些bug,不过都很快解决了大概是26号那天晚上,我第一次提交了代码,第一次提交格式出错,第二次提交初中级用例输出合法结果,高级用例错误。我在论坛里留言,第二天早上判题人员回复我说有个消费节点的需求没满足,检查了一下是超时退出的时候有些细节的东西没处理好,改了之后再次提交。出来的结果居然是第14名。当时的我真的大喜过望,而且更让我开心的是我的初中级用例竟然都是赛区最优解满分,真的没想到我那么简单的一个方案居然可以得到那么好的结果,甚至有点担心主办方看了我的代码会不会直接取消我的资格,感觉自己完全是在投机取巧。(结果好的原因我觉得主要还是因为当时服务器的价格比较便宜,直连是相对比较好的选择,最优解的服务器也大多在消费节点上,后来加了服务器的费用,再后来复赛情况进一步复杂化,这样做的结果就每况愈下了。)高级用例结果不好,主要还是我的算法费用流太慢,我的第一版代码,800节点的高级用例跑不到300次费用流(因为大多数点直连,所以速度还快一些,如果更一般的情况我估计只能跑100次)。

或许每个人都容易陷入自己的思维定势之中,一旦想到一种解决方案就很难再跳出来了,这也是与别人交流可以学到更多东西的原因所在。后来直到复赛我都没有跳出上面的的框架,我做的一切工作都只是在上面的基础上修修补补。大概这也早早注定了我不可能晋级决赛吧。

初赛(4月1日-4月5日)

初赛之前就有消息说服务器价格会调高,我当时就意识到这样做肯定对我不利,因为这样的话最优解中直连的点很可能会变少,而我的解决方案里大部分服务器都是直连的。此外,服务器价格的提高意味着最优解的服务器数量更少了,需要删掉更多的点跑更多次费用流,这样一来我费用流满的劣势就更明显了。

1号那天早上,醒来第一件事就是去官网看排名,有点意外,排名居然没变,还是14. 不过往下拉,可以发现很多队伍分数很低,应该是异常了,等他们调好bug,恐怕会被超。那天我们师门春游,不过我一天都忧心忡忡,一直担心掉排名,每隔几十分钟就看一下。到那天晚上,排名大概掉到了20上下。我已经非常慌了,因为完全不知道该怎么优化,按照这个势头下去,被挤出前32是分分钟的事情啊。

当时看到netcan说自己高级用例SPFA写的费用流可以跑1200次,而我的却只能跑两三百次,觉得百思不得其解。由于我是用邻接矩阵存图的,矩阵很大,如果用auto变量会栈溢出,所以我static了,我在考虑是不是这个导致的,我还考虑了一下改成vector容器会不会更好一些。不过琢磨了半天我还是觉得这些应该都不是问题的关键,至少不会造成几倍的效率差别。后来的几次改进也都证明数据容器不是影响效率的关键,算法搜索过程的设计才是关键。

2号那天,我偶然发现了自己启发式算法中的一个小bug。删点的时候,如果某个点删除之后费用并没有下降,那么这个点在整个删点过程中都不可能被删除,所以应该把这个点记录下来,后面就不需要再尝试删除这个点了。我在记录的时候出了点小差错,所以做了很多次无用的费用流。改掉之后,排名再次从20左右回到14左右。在一个自己已经不知道怎么优化的代码里发现小bug简直就像从抽屉里发现自己以前放的钱一样开心!

3号,排名又开始刷刷地往下掉,那天一整天又是对着代码毫无办法。傍晚的时候,我又开始在网上乱搜,偶然搜到了图的存储方式——邻接表和邻接矩阵,我就想干脆看一下吧。首先那里介绍了邻接表和邻接矩阵各种的优缺点,邻接矩阵比较直观,但是不存在的边也占用空间。看到这里,我突然突然意识到自己的一个失误,我在邻接矩阵里直接把不存在的边的cost定义为一个很大的数字,但是在搜索的时候,这个不存在的边也是需要被查找一遍的!本来是一个稀疏图,我却把它处理成了稠密图,怪不得会那么慢!怪不得SPFA处理稀疏图的优势在这里荡然无存!我立刻开始修改代码,记录了与每个点相连的点,然后在费用流查找的时候只在这些记录里查找。结果,费用流的速度提升了三四倍,原先高级用例的删点过程都来不及执行完,改完之后已经腾出了很多时间来跑换点流程。那天晚上,我提交代码之后名次提升到了11.

4号,实际上已经没有什么大的优化了,只是对删点和换点的具体步骤做了一些微调,有那么一点针对用例调整的意思吧,4号晚上最后一次提交代码后,我的排名是15左右。

5号,初赛最后一天,那天早上一起床,我就发现自己的排名掉到了19,蛮害怕的,不过那一天,我基本上没有改代码了,一来实在不知道怎么改了,感觉在那个框架内已经没法再优化了,要改只能全部删除重写了,但一天的时间是绝对不够的;二来我也是赌了一把,依据前几天的赌经验,赌自己不会一天下落10名以上。那大概是整个比赛最漫长的十几个小时了,几乎所有的队伍都在提交,我们队和上下的队伍分差都十分接近,一转眼直接就是5-10名的名次变化。晚上,看到自己的排名不停地刷新下限,23,24 25,真的有点把命运交给上天的感觉。终于熬到了初赛的最后一秒,成绩定格在26,当时也真是长长舒了一口气。(由于判卷延迟,以及少数人最后提交失败的处理,后来最终排名是27)。

关于队友

上面一直没有提到我的队友,实际上,初赛的代码的确是我一个人写的,不过我还是拉了两个队友的,一个是同师门的同学,一个是室友。不过他们当时也都挺忙,再加上我也不知道如何统筹规划3个人的任务,所以就全部自己干了。复赛的时候,我把写好的费用流发给他们,让他们也一起写启发式算法。回头想来,也的确是我没有安排好任务,大概是平时太习惯于单干吧。其实虽然看别人的程序是一件蛮烦的事情,不过还是可以分配一些子任务的,例如分析case数据,例如写一个输出文件合法性检查的程序。如果能有更给力一些的队友,甚至可以让他去试一试其他费用流的效率。

一个人走的更快,但只有通力合作才能走的更远。我还是太不善于领到一个小队,太不善于给别人分配任务,以后一定要多加锻炼。

复赛(4月8日-4月25日)

惊险地通过复赛之后,我就意识到自己慢得想龟速一样的费用流必须重写了。之前在群里看到zkw的速度比较快,于是我就开始研究zkw费用流。代码很短,可是我看了好久都没看懂他的距离角标究竟是什么意思。由于这不属于教科书上的经典算法,所以根本找不到任何能让我看懂的解释。幸运的是,偶然发现了某个参加这次比赛的人分享的zkw费用流模板(zkw最小费用流模板)。这个模板是用邻接表写的,所以我也顺便学习了一下邻接表写法,完全抛弃了之前的邻接矩阵。

不得不承认,csdn上基于这道赛题的模板帮了我很大的忙,如果仅仅看zkw写的东西,不知道我还要看多久才能搞懂算法的含义,毕竟这个问题的背景我都很清楚了,看起来更容易理解。zkw那短短二三十行代码,我研究了两三天,找遍了各种资料,又找例子按着他的代码在纸上写写画画,终于弄懂了他的距离角标是什么含义(过些日子等我有空了我会花时间写一个对这个算法的入门介绍文,希望未来像我这样的小白学习这个算法的时候能少走一些弯路)。其实弄懂了原理之后,写代码是很快的,看代码看了三天,写代码只用了不到一天,属于我自己的zkw费用流就出炉了。测试了一下,初赛800节点的图可以跑近3000次,是之前的4倍。

实际上后来我又想到了一个优化,其实上面已经提到了,那就是两点之间的上行链路和下行链路不可能同时存在流量,所以两点之间的链路没有必要存4条,只需要存2条就够了。一开始两条都是正权;当某一条正权路有流量时,另一条正权路可以暂时移除,用一条负权路来取代;如果后面这条负权路被用掉,可以再把那条正权路拿回来。这样一来,又可以少搜索一半的点。我没有用这个改进测试初赛用例,不过估计效率是处理之前的2倍左右。做了这个改进的费用流就是我最终的费用流版本,跑复赛的高级case90秒可以跑2000次左右,看群里其他同学的发言,基本上也就是zkw费用流的主流速度了。

费用流方面我得到了两个启示。第一,程序效率的提升主要还是应该着眼于算法设计层面而非数据存储层面,如果总是盯着数据存储层面,可能大大降低了程序的可读性而效率提升却微乎其微;有时候对问题的本质认识深一点,你就可以调整策略省下很多做无谓搜索的时间。第二,还是要多看别人的代码。我之前是很讨厌看别人的代码的,因为每个人的思路不一样,去读懂别人的思路特费劲。不过,如果你总是自己写的话,你可能永远不会明白为什么同样的算法,你写出来的代码的效率比别人低了那么多。只有多看牛人的代码,才能发现自己的一些不良习惯。否则,你写再多的代码,也只是在做低水平的重复而已,最多只是熟练,并没有获得能力的提升。

说完费用流,就该说启发式算法的问题了,可是到这里我实在觉得没太多可以写的东西了,因为复赛的我还是没有跳出初赛删点换点的框架。复赛的题目增加了节点部署成本,实际上相当于变相增加了服务器成本,这样一来,可能最优解里面非直连的情况就更多了,所以我原先的方法越来越难以取得好的效果。此外一个十分巨大的变化是复赛的服务器分了档次,我曾经考虑过能否在确定服务器位置之后,把服务器档次的确定整合到费用流里,例如把服务器升级费用转化为链路费用等等。不过想了想还是不可行。实际上,选择哪些服务器进行升级仍然是选址问题,所以恐怕还是NP hard,根本不像初赛那样确定服务器位置之后就变成了简单的P问题。最终,我用了最简单的服务器档次确定方案,那就是一开始全部设为最高档次,然后跑完费用流,对服务器档次做调整。跑了一些case,事实证明这并不是一个好方案,这样可能使用了很多高档服务器,从而大大提升了cost。

复赛的第三批用例,我提交代码的排名大概在十几。后来有人用求解器算了线下case的解,我发现基本上没有用高档服务器,所以我投机取巧了一下,直接在代码里限制不使用5档以上的服务器,费用一下子减少了几万,新代码线上跑进了前8名。不过后来专家组明确表示不支持调参,此外也有人对服务器的费用提出了改进意见,我就知道这种投机取巧的方法在复赛里肯定是行不通了。果然,后来第一次正式复赛的时候这种方法直接导致一个case超时(至今不知道是我的程序bug还是服务器抖了一下,也可能是后者因为很多人都超时了),其他几个case结果也很差。不过第一次复赛时网站出故障,所以比赛延期了。

延期多出来的两天,我在服务器档次上限的限制上做了一些研究,我的方法是限制不同的服务器档次上限,花个十几秒的时间跑一下限制到每一种档次的情况,选出效果最好的那个,然后剩下的时间沿着跑的最好的那个往下跑。25号那天下午给出的练习用例,我的这个代码居然跑到了第6名,这让本来已经不抱希望的我又有了一丝希望。不过晚上正式用例放出来后,我又被彻底拉回了现实。我又在服务器档次上改了几次,最后的结果都很差。期间队友也交了一次他写的退火,结果和我的也差不多。最终我们也只能眼睁睁得看着名次掉到20左右。我也只能安慰自己说,还是让更好的代码代表我们赛区去深圳争光吧,我们的渣渣代码如果进了决赛岂不是给赛区丢脸了。

尾声

对我来说,忙了一个月的比赛结束了,虽然自己最后的成绩很渣,虽然早就明白自己不太可能进决赛,但一点小小的失落还是难免,特别是看了决赛好玩的设置之后(从单机游戏变成了博弈游戏)。想来自己的积累还是太少太少,毕竟读研这两年都没正经写过代码了,靠的完全是本科的底子,当时硬撑着把C++primer看了一遍,现在大概忘了一大半了。另外由于非计算机专业,数据结构和算法的一些东西接触的还是比较少,能有幸走到复赛已经是谢天谢地了。

能通过复赛获得华为的实习机会心里还是很激动的,之前分享会的时候一位同学说过,在华为有很多优秀的人,和他们朝夕相处,你也会不断地提升自己的能力。我希望自己能在华为遇到更多优秀的朋友,希望和他们一起提升自我,超越自我。

手边有一本参加复赛时拿到的华为系列故事书,厚积薄发。“厚积是个过程,如同执着爬行的乌龟,艰难前行,孤寂落寞。薄发是个结果,如同绚丽绽放的烟花,腾空而起,万众瞩目。”愿自己忍得了厚积的落寞。

2017华为软件精英挑战赛参赛过程回顾与心得相关推荐

  1. 2017华为软件精英挑战赛小结

    // 2017华为软件精英挑战赛小结 // 不说废话,直接上货!希望对目前的参赛者,或日后学习的人,提供一些参考和思路. #include <赛题说明.pdf>    //  见附录文件 ...

  2. 2017华为软件精英挑战赛决赛思路分享

    大家好,我是月光. 历时一个多月的软挑终于落下了帷幕,收获了一个还不错的名次.这个不错是对我们自己而言的,可能对于观众来说,记住的永远只会是第一名,而其他角色终会随比赛过去而被遗忘.其实本身我希望过的 ...

  3. 2019华为软件精英挑战赛参赛心得

    1. 说在开头: 我们是来自江山赛区的[我是一条大锦鲤大锦鲤我们不会死锁呀死锁呀]队伍,这个队名不止一次被我队友调侃为沙吊/哈哈哈,开头我不得不舔一波华为公司,华为公司对这个比赛准备的真的很好,很贴心 ...

  4. 2017华为软件精英挑战赛解分析

    后经在复赛赛题上测试,效果并不好,只适合部分数据集,并且没有理论支持,放出来只为启发-- 以下方法初中级样例1s以内,高级样例10s内出最优解-- 不随机,无启发式,走优化的方法.采用反馈-迭代的方法 ...

  5. 最小费用流算法不完全指南-2017华为软件精英挑战赛

    1.前言 整个比赛历时70多天,是一场持久战,期间看了不少资料,实现了一些算法,现总结如下. 初赛的思路是启发式+费用流,启发式实现了遗传算法.模拟退火,费用流实现了连续最短路(spfa),zkw/p ...

  6. 2017华为软件精英挑战赛系列一

    看到题目时,首先就是读懂它.以下就是我对题目的一些分析. 需要解决的问题 在满足所有的住户小区视频播放需求的基本前提下,如何选择视频内容存储服务器放置位置,使得成本最小. 本次赛题通用性描述 网络结构 ...

  7. 2017华为软件精英挑战赛总结

    1.题目 本次赛题是一个视频服务器的CDN规划问题 赛题包_百度网盘 2.解题思 2.1 思路一 整数规划 主要是要把模型建出来 包含了 0-1变量->是否布置服务器 边变量-> 表示该边 ...

  8. 2017华为软件精英挑战赛txt数据的读取(MATLAB实现)

    path = 'case_example\case0.txt';fid = fopen(path,'r');caseData.nodEdgUserCount = zeros(1,3);b = fget ...

  9. 2017年华为软件精英挑战赛初赛解题思路

    2017年华为软件精英挑战赛初赛解题思路 题目链接:http://codecraft.huawei.com/  常规解题思路:网络流(最小费用最大流)+ 启发式搜索算法 + 算法性能优化 1. 最大流 ...

最新文章

  1. 当程序崩溃的时候怎么办
  2. PL/SQL-2 复合数据类型
  3. mysql怎么多表备份_学习MySQL多表操作和备份处理
  4. 用Heartbeat构建Web Ha
  5. 如何做一份能忽悠投资人的PPT
  6. Junit4与junt3并存时产生的问题
  7. rocketmq在Kubernetes(k8s)中的集群配置,2m-2s-async:多Master多Slave模式,异步复制
  8. ConstraintLayout约束控件详解
  9. mysql服务性能优化—my.cnf配置说明详解
  10. FFmpeg视频截取第一帧
  11. 使用tkinter实现 loading 等待效果
  12. “麒”聚信创,共赢未来——信创解决方案分享会(首场)成功举办
  13. c语言rfmtdate函数,Ecshop后台流程图
  14. 换脸检测论文 FaceForensics++: Learning to Detect Manipulated Facial Images相关资料
  15. 琐碎的知识点(xly)
  16. 小傻蛋的妹妹跟随小甲鱼学习Python的第二节002
  17. AI即服务 AI as a Service
  18. 轻松写日记---日记软件
  19. 计算机网络原理总结(英文版 第五版) Chapter1
  20. Java【网络编程1】使用 UDP 的 Socket API 实现客户端服务器通信(保姆级教学, 附代码)

热门文章

  1. vue仿卷皮折扣App
  2. Windows protected your PC
  3. 游戏素材下载地址收藏
  4. 前端求职难?那是你没看见这个
  5. 自学python第四课——字符串运算符、字符串内置函数、字符串常用方法总结
  6. 关于谷歌/狐火等浏览器使用window.close()无法关闭网页问题
  7. 直方图移位可逆水印MATLAB代码,基于图像插值和直方图平移的可逆水印算法
  8. imac pro 接显示器_您应该购买iMac Pro,还是等待模块化Mac Pro重新设计?
  9. 梅科尔工作室-王静琳-鸿蒙笔记3
  10. Proxmox VE Install