如何出题(翻译)

原文链接:https://www.topcoder.com/how-to-come-up-with-problem-ideas/

过去几年,我写了许多题目,提供给包括Topcoder SRM、Codeforces、ICPC以及许多别的在线平台。当我被问及我如何想出这些题目的时候,我常常不知从何说起。于是我决定静下心来,就这个话题写一点我的看法。

在深入具体例子之前,我想解释一下我称之为「出题思维」的东西。每天,我看着平凡的事物,然后我的意识就自动开始思考把它改造成一道算法竞赛题。当我参加比赛的时候,我也总是在思考如何能够把在这场比赛中用到的技巧化用到新的题目中去。出题的灵感无处不在!这是我看待世界的方式。下面我将给你展示几个例子,还有更多的例子我没有写出。

1. 从一个解法开始逆向思考

这个技巧最适用于学习新东西。我学一个新技巧,然后写一个关于它的题目去强化我对它的掌握。我常常在一个未解决的比赛题目或者一些博客中发现这类知识点。我通过出一个与它有关的题把它内化于心。

一个例子是Yet Another Tree Problem,我最近学习了点分治,我看了一些关于它如何运作的例子,然后尝试扩展它。我加入的新变化是凸包知识点,我懂得怎么样连接两个知识点,这一本领愈发纯熟。我认为这两者的组合是有趣的应用,简洁的题面也是一个额外的优点。

对我来说,我不会觉得大部分这样的问题有很多原创性,它们使用众所周知的知识点,难度一般在中等和困难之间。在这种难度层次上,你很难写一个又好又简单的问题,因为它总是需要一些特定知识。就我个人来说,我不认为这些问题一定是糟糕的,它们对于一个大题量的比赛来说是必要的,并且可以成为更高级的知识点的引路人。

我利用这个出题方法出的另外一些题目:

Uniform Trees,我想出了这道题是因为我最近学习了「从小到大」技巧,我想利用的关键想法是只保存和计算必要的dp状态。

Hamiltonian Spanning Tree,我知道在树上找匹配的贪心算法,并且发现它能推广到在树上找两个匹配。我伪装了题目,所以这两者的联系不是那么显然。

LoopyPath,我想写个关于卷绕数的问题。我得加一些限制,我们只能访问每个网络至少一次,去保证可追踪。(否则它就等价于网格图上的斯坦纳树)

TrianglePainting,我学习了闵可夫斯基和。你也可以利用凸包面积的线性期望来得到这个问题。

Robot Arm,这可能是我写的第一次数据结构问题,我把线段树与平面的旋转/平移矩阵组合起来。

SegmentCutting,I wanted to write something about sweeping in a circle. I thought hiding some part of it as “square of euclidean distance” was nice, and it works for arbitrary polynomial functions on the difference of x and y coordinates separately.

(待施工)

通常,我为第一次想出这样的问题而激动,因为对我来说这是一个新的知识点。虽然这种方式的确有更高的风险与之前的题发生撞题,很难跟上创意的潮流,我仍然需要时不时地改进。我认为几乎所有人都可以利用这个方法来出题,它会帮助你提高,如果你在尝试学习新的标准算法的话。

2. 随机想一些点子然后混合它们

与之前的方法相反。有许多现成的材料可供你利用、组合成新的题目。比如树、数组、子序列、异或、回文串等等,你可以随机组合一些点子,然后看看结果是否可解决,是否有趣。

这种方法的一个例子是BridgeBuilding。我想写一个题目,在给图加几条边后,最小化直径,但它的小范围数据规模看上去很乏味,找出简洁的通用做法貌似很困难。我尝试找一些特殊的图,确保它依然足够有趣。我最终想出了现在的版本,在看到一节丢失了许多阶梯的梯子后,我思考两个平行线的图,并有边在两图之间穿梭。我花了一点时间去得到正解,并且多次误入歧途。它最终成为了一个困难场的非常好的问题。

 

posted @ 2021-03-06 13:10  AngelKnows  阅读(308)  评论(0)    收藏  举报