【Tools】使用批處理檔案對拍程式
關於對拍
OI比賽的時候經常會發生這麼一種情況:
第X道題,寫好了暴力並能夠保證暴力的正確性,但突然想到了一個更為高效的演算法,但無法確定程式是否正確,這個時候,就要使用對拍解決問題。
有些人是用c++程式進行對拍的,而我喜歡用bat檔案(因為寫起來短啊)。
我們假設這道題的題目名為problem,資料生成的可執行程式名為random.exe
兩個程式的可執行程式名名稱為problem1.exe和problem2.exe。
先發一波對拍效果圖
最後一行是我打了Ctrl + C
終止程式因為這樣才能截圖
兩個版本的bat對拍
cpp內重定向寫法
首先是第一種版本,就是三個源程式中都寫了freopen,且random.exe的輸出檔案為problem.in,而兩個程式所對應的輸出為problem1.out和problem2.out
接下來就是對應的bat
@echo off
:loop
random.exe
problem1.exe
problem2.exe
fc problem1.out problem2.out
if not errorlevel 1 goto loop
pause
goto loop
bat內重定向寫法
其次是第二種版本,就是三個程式的freopen都不被執行,相比來講也更加隨性,畢竟名字可以亂取了
對應的bat,效果和第一種是一樣的。
@echo off
:loop
random.exe > problem.in
problem1.exe < problem.in > problem1.out
problem2.exe < problem.in > problem2.out
fc problem1.out problem2.out
if not errorlevel 1 goto loop
pause
goto loop
兩種程式碼可以自己參考使用,各有優劣。
對於bat內部的東西是什麼意思還是解釋一下吧雖然對拍這種東西靠背啊。
我拿第二個bat解釋一下。
首先第一行@echo off
關閉輸入顯示,如果你單純地想確認一下正確性的話這句話就一定要打上,否則東西會太多的,如果不打,上結果圖:
東西有點多,就很亂。。如果不想看到這種東西模糊你的眼睛就還是打上吧。
其次是第二行的
:loop
這是個標誌,為了使用後面的goto
。這個功能相信大家使用c++時一定為了好玩而使用過。 第三行
random.exe > problem.in
,意思是執行random.exe並將程式執行結果匯入problem.in。 第四行和第五行,基本格式就是
problem.exe < problem.in > problem.out
,基本意思就是執行problem.exe,輸入檔案定向到problem.in,輸出檔案重定向到problem.out,說的簡單點就是執行problem.exe,從problem.in中讀入資料,在將程式結果輸出到problem.out中。 第六行
fc problem1.out problem2.out
,fc
是比較的意思,這句話就是對兩個out檔案進行比較。 緊接著是第七行
if not errorlevel 1 goto loop
,errorlevel
是上一條命令的返回值,上一行的fc
在比較的兩個檔案相同時返回0,不同時返回1, 這一行的意思就是,如果
fc
返回的不是1,就跳到:loop
,進行下一個迴圈。 再下一行
pause
暫停,一旦fc
返回1,就會執行到這一行,暫停程式,給你時間看資料。 具體效果:
goto loop
,看完資料,按下任意鍵結束暫停,繼續迴圈。
關於關於對拍的事兒就講到這裡,接下來貼一發在網上看到的隨機數的優化。
隨機數優化
優化起源:在我們寫隨機程式的時候會寫出如下的片段:
srand((unsigned)time(NULL));
或者是
int seed = time(NULL);
srand(seed);
可惜的是time(NULL)
每秒更新1次,相當於1秒內生成的隨機資料是一模一樣的!這個太慢了,我們需要更優秀的隨機函式。
那麼有沒有什麼變的更快的隨機數種子?有!windows自帶了一個隨機數發生器:%random%,它的值就是一個隨機整數,可以在命令列裡呼叫。
那接下來就好辦了,我們把這個數傳給rand.exe用來當隨機數種子就行了。
(⊙o⊙)…怎麼傳引數呢?
這就要使用到c++main()函式中那個被省略的引數了。
你也許會問,main()難道省略了什麼引數嗎???
不好意思,答案是是的。
本來的main()應該是長成這樣子的。
int main(int argc, char *argv[]) {
}
和都有什麼用呢?
實際上這兩個就是傳入引數, 是引數個數, 是引數表,從1開始。
接下來就好辦了,我們只要把%random%傳給random.exe就行了。
具體操作就是把第二個bat中的random.exe > problem.in
改為random.exe %random% problem.in
,在random的源程式中也要對應地修改一下。板子在下面給出。
bat和random板子
bat
@echo off
:loop
data.exe > in.txt
solve1.exe < in.txt > out1.txt
solve2.exe < in.txt > out2.txt
fc out1.txt out2.txt
if not errorlevel 1 goto loop
pause
goto loop
random
#include<ctime>
#include<cstdio>
#include<cstdlib>
#include<sstream>
#define randint(l, r) ((l) + rand() % ((r) - (l) + 1))
int main(int argc, char *argv[]) {
int seed = time(NULL);
if (argc > 1) {
std::stringstream ss;
ss.clear();
ss << argv[1];
ss >> seed;
}
srand(seed);
return 0;
}