用 batch 解决小问题

个人博客:https://原子核.eu.org/
我在大同一中初中举办的所谓 “求知杯” 的竞赛里,看到了一道很霸道的题。当时是第 6 题,题目内容是:
将集合 {1, 2, ……, 19} 中每两个互异的数作乘积,所有这种乘积的和为______.
很明显这道题可以通过强攻硬算做出来,当时也的确有人这么做,那个人算出来的结果和电脑算出来的结果非常相近。于是我开始考虑用编程实现大量计算。学校电脑没有 g++,所以我选了最基础的 batch(批处理)来编写。
根据题意,我们需要计算一些乘数有规律的乘法,它们分别是:(Bilibili没有代码块,姑且用引用块低配平替一下)
1×2=
1×3=
……
1×19=
……
2×3=
2×4=
……
2×19=
……
17×18=
18×19=
为了计算方便,我们假设两个乘数分别是变量 t1
,t2
。建立这两个变量:
set t1=
set t2=
set /a t1=1
set /a t2=%t1%+1
::定义t1=1,t2=2
这样我们就得到了两个变量,分别是 t1==1
,t2=2
。
之后,我们还需要一个用于存放每一步的结果的变量 tmp
和用于累加结果的变量 num
。建立这两个变量:
set num=
set /a num=0
set tmp=0
我们需要两个乘数依次滚动,在将每个【第一个乘数】所对应的【第二个乘数】遍历。为此我们需要两层循环。小循环是【第二个乘数】的循环,大循环是【第一个乘数】的循环。每个【第一个乘数】中,都需要将所有的【第二个乘数】的可能性都算完。由于在 batch 中循环的写法太过于流氓,在不追求运行速度的情况下,我更愿意使用标签和跳转来实现循环。
具体写法如下:
:loop
::内容
goto loop
:bigloop
::内容
goto loop
::对没有写错,这里大循环结束后要进入小循环
而且,如你所见,这种写法也不依赖于循环之间的包含关系,比较灵活,随心所欲。
接着我们开始写小循环。
在小循环中,我们要实现以下操作:
用已经定义好的
t1
和t2
来计算乘积,写入tmp
;将
tmp
作为加数累加到num
中;判断:若
t2==19
,则跳转到大循环进行新的【第一个乘数】;否则计算同一个【第一个乘数】的下一个【第二个乘数】。
即:
:loop
::小循环
set /a tmp=%t1%*%t2%
::计算乘积
set /a num=%num%+%tmp%
::写入乘积
if /i %t2%==19 goto bigloop
::若t2==19,跳转大循环(t1自增,t2原始值自增)
set /a t2=%t2%+1
::否则只有t2自增
goto loop
在大循环里,我们需要实现:
t1
自增;将
t2
赋值为t1
后的第一个互异数;判断穷举是否完成。
即:
:bigloop
::大循环
set /a t1=%t1%+1
::t1自增
set /a t2=%t1%+1
::t1后第一个互异数赋值t2
if /i %t2%==20 if /i %t1%==19 goto result
::若穷举完成则输出结果
goto loop
::否则进入小循环
最后写 result
标签用于输出结果:
:result
echo 计算结果:%num%
整体框架出来以后,程序全文进行一些优化,加上题目和日志输出,加上结果暂留处理。完整代码如下:
@echo off
title 求知杯第6题
color f0
cls
echo 题目:将集合{1,2,……,19}中每两个互异的数作乘积,所有这种乘积的和为_.
echo 按下任意键开始计算
pause >nul
echo 题目:将集合{1,2,……,19}中每两个互异的数作乘积,所有这种乘积的和为_. >求知杯第6题.txt
::删除运行记录
set num=
set /a num=0
set t1=
set t2=
set /a t1=1
set tmp=
set /a t2=%t1%+1
::定义t1=1,t2=2
:loop
::小循环
set /a tmp=%t1%*%t2%
::计算乘积
set /a num=%num%+%tmp%
::写入乘积
set tmpecho=
set /a tmpecho=%num%-%tmp%
echo 计算过程:%tmpecho%+%t1%×%t2%=%num%
echo 计算过程:%tmpecho%+%t1%×%t2%=%num% >>求知杯第6题.txt
if /i %t2%==19 goto bigloop
::若t2==19,跳转大循环(t1自增,t2原始值自增)
set /a t2=%t2%+1
::否则只有t2自增
goto loop
::回到小循环
:bigloop
::大循环
set /a t1=%t1%+1
::t1自增
set /a t2=%t1%+1
::t1后第一个互异数赋值t2
if /i %t2%==20 if /i %t1%==19 goto result
::若穷举完成则输出结果
goto loop
::否则进入小循环
:result
echo 计算结果:%num%
echo 计算结果:%num% >>求知杯第6题.txt
echo 按下任意键退出程序
pause >nul