博主发这篇文章的时候国赛早就结束了,仅仅是出于给自己留个纪念以及交流讨论的目的写的博客。所以如果你对我不在比赛那几天发的行为感到不满,请直接退出就好,我也没觉得自己的想法多么优秀,能够断言自己是答案。不当之处欢迎各位大佬指正,但是抬杠还请放过。
包括CSDN、B乎在内的很多平台也都发布了一些解析。这里插句题外话。凡是在比赛期间在这些平台发布答案的统统不要全信,因为你要明白,这么大胆的人十有八九是不打比赛的,不然不但方便了自己的竞争对手,而且被DQ岂不血亏?既然不打比赛,他对题目的思考就不可能很深入,一个晚上三道题目就全部解析完了,那解析的质量可想而知。而且你要是加了那些所谓大佬留下的QQ号或是群,是很有可能被官方查到的,因为你比赛前预留了自己的QQ(小号可能勉强能躲过去,但是还是建议诚信比赛,不然就算有了他的思路,你不知道来龙去脉也不好改进模型,也就省一省二封顶)
另外,那些发布解析,但是只是笼统地提一下这题要用某算法或者某模型的统一当P处理。一个算法应用到实际中有无穷无尽的细节,甚至可能超出了实际计算机的算力,需要进行大量优化,或者会发现需要加入其它的模型或算法进行辅助。
此外,动不动就神经网络,甚至LSTM,transformer的绝对不要信。建模比赛很少会涉及过于复杂的神经网络,因为神经网络的优化本身就是一个无底洞,无数教授都还在研究的东西,怎么可能放给你一个本科生做?
博主敢发解析出来也是有点底气的,博主之前有过ACM经历,就读于人工智能专业,做过一些机器学习和神经网络的项目与科研。具体可以查看博主以前的博客。(但是奖项和论文博主后面都不会透露,因为这个有点涉及隐私问题,希望大家理解)
(顺便讲个有意思的事,2020美赛建模的B题叫“最坚固的沙堡”,2020国赛的B叫“穿越沙漠”,大家自己体会,23333)
考虑如下的小游戏:玩家凭借一张地图,利用初始资金购买一定数量的水和食物(包括食品和其他日常用品),从起点出发,在沙漠中行走。途中会遇到不同的天气,也可在矿山、村庄补充资金或资源,目标是在规定时间内到达终点,并保留尽可能多的资金。
游戏的基本规则如下:
(1)以天为基本时间单位,游戏的开始时间为第0天,玩家位于起点。玩家必须在截止日期或之前到达终点,到达终点后该玩家的游戏结束。
(2)穿越沙漠需水和食物两种资源,它们的最小计量单位均为箱。每天玩家拥有的水和食物质量之和不能超过负重上限。若未到达终点而水或食物已耗尽,视为游戏失败。
(3)每天的天气为“晴朗”、“高温”、“沙暴”三种状况之一,沙漠中所有区域的天气相同。
(4)每天玩家可从地图中的某个区域到达与之相邻的另一个区域,也可在原地停留。沙暴日必须在原地停留。
(5)玩家在原地停留一天消耗的资源数量称为基础消耗量,行走一天消耗的资源数量为基础消耗量的2倍。
(6)玩家第0天可在起点处用初始资金以基准价格购买水和食物。玩家可在起点停留或回到起点,但不能多次在起点购买资源。玩家到达终点后可退回剩余的水和食物,每箱退回价格为基准价格的一半。
(7)玩家在矿山停留时,可通过挖矿获得资金,挖矿一天获得的资金量称为基础收益。如果挖矿,消耗的资源数量为基础消耗量的 倍;如果不挖矿,消耗的资源数量为基础消耗量。到达矿山当天不能挖矿。沙暴日也可挖矿。
(8)玩家经过或在村庄停留时可用剩余的初始资金或挖矿获得的资金随时购买水和食物,每箱价格为基准价格的2倍。
请根据游戏的不同设定,建立数学模型,解决以下问题。
注1:附件所给地图中,有公共边界的两个区域称为相邻,仅有公共顶点而没有公共边界的两个区域不视作相邻。
注2:Result.xlsx中剩余资金数(剩余水量、剩余食物量)指当日所需资源全部消耗完毕后的资金数(水量、食物量)。若当日还有购买行为,则指完成购买后的资金数(水量、食物量)。
说实话,这题做下来感觉基本全是算法,可以说是国赛中史无前例了。也算是一次创新吧,说明现在建模比赛越来越重视小队的编程能力和算法能力,比较建议以后组队的时候尽量寻找一个编程水平还不错,最好有ACM或者机器学习基础的队员。
这道题目一般稍微有点ACM基础的人应该是一秒就能看出动态规划的。用一个数组 d p d a y , l o c a t i o n , w a t e r , f o o d dp_{day, location, water, food} dpday,location,water,food表示此状态下的最大金钱。但是,打过ACM的会发现,这里30*30*400*600已经2e8了,你要是碰上商店,那后续状态还得是400*600,明显爆复杂度了。虽然建模没有ACM那么严格的时间限制,但是你一个代码跑一天不论是性能还是对你Debug来说都是难以接受的。
所以我们还是得稍做优化。
首先,那30个点可以仔细看一下,你会发现有些点去掉不会影响最优解,例如第一关3号,走旁边边绝对不比走它差(其实是绝对比它好),那我们完全可以把它去掉,这么一筛选,首先点的数量得少一半左右。
其次,我们一直在村庄逗留必定不是最优解,因为你相当于白耗资源,所以我们只需要在进出村庄的时候购买就可以了。事实上,还可以再继续优化,我们在村庄逗留的时间不会很长,你可以假定有个上限,比如3天,那我们进村庄时只需要确保3天的资源即可,出来的时候可以遍历一下购买,这样又剩下一半复杂度。
再来,虽然水和食物的名义上限是背满负重,但至少在我们的例子中,没有人会傻到全买其中一样的,因为村庄还有段距离。这其中,食物又比水贵一些,在村庄买食物的损失就会更大。所以我们可以调低它们的上限,比如水是300,食物500,这样也降低了复杂度。
除此以外还有些比较复杂的优化,比如差额数组(用和水的差额来代替直接表示食物)等,这个就比较麻烦,得不偿失。
事实上,只要你把我说的这三项优化做好,基本上是完全能在一个可以接受的时间内完成DP的。
答案就不提了,虽然跟其他学校的人也对过,但是也不好放出来,大家听懂思路最重要。
递推方程如下:
d p d , l , w , f → { d p d + 1 , l , w − w c o n s u m e , f − f c o n s u m e d p d + 1 , k , w − 2 × w c o n s u m e , f − 2 × f c o n s u m e ( k 与 l 相 邻 , 且 当 天 非 沙 暴 ) d p d + 1 , l , w − 3 × w c o n s u m e , f − 3 × f c o n s u m e + b o n u s ( l 是 矿 山 ) dp_{d, l, w, f}\rightarrow\left\{ \begin{aligned} dp_{d+1, l, w-w_{consume}, f-f_{consume}} \\ dp_{d+1, k, w-2\times w_{consume}, f-2\times f_{consume}} & (k与l相邻,且当天非沙暴) \\ dp_{d+1, l, w-3\times w_{consume}, f-3\times f_{consume}} + &bonus(l是矿山)\\ \end{aligned} \right. dpd,l,w,f→⎩⎪⎨⎪⎧dpd+1,l,w−wconsume,f−fconsumedpd+1,k,w−2×wconsume,f−2×fconsumedpd+1,l,w−3×wconsume,f−3×fconsume+(k与l相邻,且当天非沙暴)bonus(l是矿山)
此外,如果移动时进入村庄,或离开村庄,或者在村庄停留都有一个额外的转移,即购买。
三种情况比较类似,但是细节上有差距,博主只放一种,即进入村庄,剩下两种意义不大,浪费版面,交由各位聪明的读者自行体会。
d p d , l , w , f → d p d + 1 , v , w − 2 × w c o n s u m e + i , f − 2 × f c o n s u m e + j − i × p r i c e w a t e r − j × p r i c e f o o d dp_{d, l, w, f}\rightarrow dp_{d+1, v, w-2\times w_{consume}+i, f-2\times f_{consume}+j} - i\times price_{water} - j \times price_{food} dpd,l,w,f→dpd+1,v,w−2×wconsume+i,f−2×fconsume+j−i×pricewater−j×pricefood
其中水和食物必须满足负重和钱数需求,即 w e i g h t w a t e r × ( w − 2 × w c o n s u m e + i ) + w e i g h t f o o d × ( f − 2 × f c o n s u m e + j ) ≤ w e i g h t l i m i t weight_{water}\times (w-2\times w_{consume}+i) + weight_{food}\times (f-2\times f_{consume}+j)\leq weight_{limit} weightwater×(w−2×wconsume+i)+weightfood×(f−2×fconsume+j)≤weightlimit p r i c e w a t e r × i + p r i c e f o o d × j ≤ d p d , l , w , f price_{water}\times i + price_{food}\times j\leq dp_{d, l, w, f} pricewater×i+pricefood×j≤dpd,l,w,f
这道题目跟第一问唯一的不同在于,无法使用上帝视角,而是每天了解当天天气并在不知道未来天气的情况下决策。这题我们的思路是使用启发式搜索(A*)。启发式搜索决策是根据一个评估函数h(x) = f(x) + g(x),其中f(x)表示已经有的收入,g(x)表示未来期望的收入。
评估函数选择的核心在于g(x)的选择,g(x)的预测越接近实际值,选择出最有路径的概率就越高。
我们对于评估函数g(x)的选择是利用期望DP求出每个状态下的 g d a y , l o c a t i o n , m o n e y , w a t e r , f o o d g_{day, location, money, water,food} gday,location,money,water,food,期望DP是DP的一个应用,各位读者想了解的话可以研究一下各种ACM的题目。
这里我们的期望是三种天气的最优后续决策期望乘上对应天气出现的概率。
g d a y , l o c a t i o n , m o n e y , w a t e r , f o o d = m a x { g s u n n y } × p s u n n y + m a x { g h o t } × p h o t + m a x { g s t o r m } × p s t o r m g_{day, location, money, water,food} = max\{g_{sunny}\}\times p_{sunny} + max\{g_{hot}\}\times p_{hot} + max\{g_{storm}\}\times p_{storm} gday,location,money,water,food=max{gsunny}×psunny+max{ghot}×phot+max{gstorm}×pstorm
具体到单个天气,期望DP的状态转移方程如下:
g d a y , l o c a t i o n , m o n e y , w a t e r , f o o d + = p w e a t h e r × m a x { g d + 1 , l , w − w c o n s u m e , f − f c o n s u m e g d + 1 , k , w − 2 × w c o n s u m e , f − 2 × f c o n s u m e ( k 与 l 相 邻 , 且 当 天 非 沙 暴 ) g d + 1 , l , w − 3 × w c o n s u m e , f − 3 × f c o n s u m e + b o n u s ( l 是 矿 山 ) g d + 1 , v , w − 2 × w c o n s u m e + i , f − 2 × f c o n s u m e + j + i × p r i c e w a t e r + j × p r i c e f o o d ( v 是 村 庄 , 且 食 物 和 水 未 超 负 重 , 也 未 透 支 消 费 ) g_{day, location, money, water,food} += p_{weather} \times max\left\{ \begin{aligned} g_{d+1, l, w-w_{consume}, f-f_{consume}} \\ g_{d+1, k, w-2\times w_{consume}, f-2\times f_{consume}} & (k与l相邻,且当天非沙暴) \\ g_{d+1, l, w-3\times w_{consume}, f-3\times f_{consume}} + &bonus(l是矿山)\\ g_{d+1, v, w-2\times w_{consume}+i, f-2\times f_{consume}+j} + i&\times price_{water} + j \times price_{food}(v是村庄,且食物和水未超负重,也未透支消费) \end{aligned} \right. gday,location,money,water,food+=pweather×max⎩⎪⎪⎪⎪⎨⎪⎪⎪⎪⎧gd+1,l,w−wconsume,f−fconsumegd+1,k,w−2×wconsume,f−2×fconsumegd+1,l,w−3×wconsume,f−3×fconsume+gd+1,v,w−2×wconsume+i,f−2×fconsume+j+i(k与l相邻,且当天非沙暴)bonus(l是矿山)×pricewater+j×pricefood(v是村庄,且食物和水未超负重,也未透支消费)
此外,你可以在递推的时候加上一些限制,比如行军的时候提前两天走(即多预留两天资源),预防后面非酋碰上连续两天沙暴啥的,这就看你自己了。
这里可以看到递推方程里少了一个维度,那就是身上钱的数量m。这里这么写其实是不正确的。那为什么我还要这么写呢?
是这样的,在第二题给的具体案例中,我们可以看到无论是挖矿收益还是初始资金相比于食物和水的价格都十分可观,我们可以假定最优路线全程未出现透支,这其实是合理的,因为确实在这两个具体案例中较优解不会出现把钱花完的情况。
所以,靠这种方法省下那个10000的维度完全合理。
最后我们可以随机生成一组天气,根据具体天气以及我们已经算好的期望DP数组进行计算。同样地,不提供代码结果,还请见谅。
众所周知,国赛的第三题一般都是开放性试题,所以一时半会儿想不到很好的解决方法或者模型是完全正常的,某种意义上甚至可以说第三题是竞赛组想借鉴学生的奇思妙想来优化专业人士的模型。
所以哪怕第三题语文建模也不要太害怕,你做得好确实加分,做不好也无伤大雅,算是在竞赛组对你实力的预期内。只要把前面的问题都做好,都做得八九不离十,第三题只要能自圆其说其实基本也拿国了。
回到这个第三题。这道大题的第三题主要是加入了一个比较讨厌的多人运动 ,问题从本质上发生了变化,本来是一个规划与决策问题,现在其实更多是一个博弈问题。
第一问的特点在于决策开局就必须确定,一旦确定好就不能更改。这里就涉及一个非合作静态博弈。
提到非合作静态博弈,就不得不提到纳什均衡。
所谓的纳什均衡呢,就是指博弈论之父约翰·纳什提出的一种在多人博弈中,任何一方改变自己的策略都不会有好处的均衡状态。
最经典的案例就是小偷难题。两个小偷偷东西被抓,但是警察拿不出任何的证据指控他们,所以把这两个小偷分开各自审问。如果两个人都不坦白,则缺乏证据,只能按照私闯民宅给两个人各判1年;如果两个人都坦白,则证据确凿,两个都会被判处8年徒刑;如果一个人坦白但是另一个否认,则坦白者会将功抵过立即释放,否认者会因妨碍公务被额外增加两年徒刑。
如果从整体来看,那必然是两个人都抵赖的收益最高,总共只有两年徒刑。但是,如果这两个小偷其实是塑料兄弟情,从很早开始就互看不爽了,那就是另一回事了。假如他坦白,如果我抵赖,得坐10年监狱,如果我坦白最多才8年;假如他要是抵赖,如果我也抵赖,我就会被判一年,如果我坦白就可以被释放,而他会坐10年牢。这么一看抵赖简直血亏,凭什么便宜了他?结果两个人都选择了坦白,一起坐了8年,变成了总体收益最低的方案。
这道题目也一样,在绝对利己的条件下,最优路线你不走,就可能便宜了别人,导致自己最后输掉。所以,不管是哪一边,理论上都会选择最优路线,只不过需要预先考虑到别人会一直跟着自己,所以需要留足水和食物。
这一问的特点在于,决策必须前一天做,从规划变为决策。
这题其实很难用计算机来模拟给出决策,其原因在于,我们的对手不太可能是傻子,他不可能做随机走或者必定走最优路线这种机械的决策,更一般地,应该说他的决策是完全不可预测的,否则就违背了现实情况(你打游戏时能提前知道别人走啥路那叫外挂)。
我们这题其实已经半语文建模了,我们提出了几个都8太行的模型,反正多少也算是水过去了。
总的来说,这题是国赛的首次实验吧,首次出主偏算法的题目,所以说实话可能各种选手也普遍缺乏这方面的经验。我也明白自己的模型有很多纰漏之处,欢迎各位同学交流指正,祝大家在以后的美赛/国赛中都能拿到O/国一的成绩。