此前写过Ubuntu下的程序对拍:https://blog.csdn.net/moon_sky1999/article/details/100353519
对拍是一种很好的纠错手段,特别是在算法竞赛中,通过对拍,可以得到有效的Debug的数据。对拍的基本原理大概如下:自己手写一个完全暴力的程序(一定要确保该代码的正确性,该代码是对拍的基础),利用这份暴力代码,与自己写的代码运行同样的数据,对比二者的结果。
举个例子:
给出一个长度为
n
n
n的序列
A
n
A_n
An,求最大连续和。(注意
A
i
A_i
Ai可能是负数)
换句话说,就是要找到
1
≤
i
≤
j
≤
n
1≤i≤j≤n
1≤i≤j≤n,使得
A
i
+
A
i
+
1
+
…
+
A
j
A_i+A_{i+1}+…+A_j
Ai+Ai+1+…+Aj最大。
最为暴力的做法大概是枚举所有的i,j,对每一个区间都进行求和,最终取最大值,输出。时间复杂度为
O
(
n
3
)
O(n^3)
O(n3)。
#include <bits/stdc++.h>
using namespace std;
const int inf = 1e9 + 10;
int n, a[10010];
int main() {
cin >> n;
for (int i = 1; i <= n; ++i) cin >> a[i];
int ans = -inf;
for (int i = 1; i <= n; ++i) {
for (int j = i; j <= n; ++j) {
int ct = 0;
for (int k = i; k <= j; ++k)
ct += a[k];
ans = max(ans, ct);
}
}
cout << ans << endl;
return 0;
}
这份代码作为暴力代码,用于对比自己代码运行的结果。
假如说我们写好的代码如下:
#include <bits/stdc++.h>
using namespace std;
const int inf = 1e9 + 10;
int n, a[10010], s[10010];
int main() {
cin >> n;
for (int i = 1; i <= n; ++i) cin >> a[i];
int ans = 0, mx = 0, mn = 0;
for (int i = 1; i <= n; ++i) {
s[i] = s[i - 1] + a[i];
mx = max(mx, s[i]);
ans = max(ans, mx - mn);
mn = min(mn, s[i]);
}
cout << ans << endl;
return 0;
}
这份代码的时间复杂度是O(n)的,但该代码是错误的,我们有不知道错误出在什么地方,需要一组数据来辅助Debug。
对拍的具体过程如下:
- 在同一文件目录下创建3个cpp文件,其中a和b分别放入自己的代码与暴力代码:
- 另外建立三个文本文件,a.txt b.txt data.txt,其中,data.txt存放data.cpp生成的数据
- data.cpp中的代码如下:
#include <bits/stdc++.h>
using namespace std;
int main() {
srand(time(0));
int n = rand() % 5 + 1;
cout << n << endl;
for (int i = 1; i <= n; ++i) {
int t = rand() % 10 - 5;
cout << t << ' ';
}
return 0;
}
完全按照输入的格式生成随机数据,注意t - 5的目的是生成的数据中存在负数。n + 1的目的是保证n >= 1。对拍数据可以很小,你的目的是找到一组卡掉自己的数据,来辅助自己Debug,数据要有可读性。同时,生成的数据一定要有普遍性,即涵盖所有的特殊情况,只是范围可以小一点。比如本题中,生成的a数组不能只是正整数,而应该满足可正可负可为0,通常卡掉自己的数据正是一些特殊的情况。
- 编译,生成三者的exe可执行文件。
由于我本地是使用的cygwin的g++环境,且已经配好了环境变量,可以直接使用终端来编译代码。也可以用其他方式来生成。
将cmd命令行添加到右键菜单的方法(注意名称使用中文可能会导致乱码问题):https://blog.csdn.net/mooneve/article/details/78821843
- 正式开始对拍过程:
在该目录下新建一个duipai.txt的文本文档
在其中添加如下代码:
color A
echo off
:loop
echo run%a%
set /a a+=1
data.exe > data.txt
a.exe < data.txt > a.txt
b.exe < data.txt > b.txt
fc a.txt b.txt
if not errorlevel 1 goto loop
pause
代码解释,讲生成的数据存入data.txt,将a和b的程序运行结果放入a.txt和b.txt中,然后进行比对,注意ab两个程序的输出格式一定要相同,共同忽略行末空格或都不忽略。
- 将duipai.txt修改名称和类型为duipai.bat,然后就可以运行了。
几点补充:
- 如果本地采用的编译器是mingw,duipai.bat也可以改成cpp生成的exe文件。
代码如下:
#include <bits/stdc++.h>
#include<windows.h>
using namespace std;
int main() {
int t = 1;
while (1) {
system("data.exe>data.txt");
system("a.exe<data.txt>a.txt");
system("b.exe<data.txt>b.txt");
cout << "test " << t << ":" << endl;
if (system("fc 1.txt 2.txt"))break;
t++;
}
return 0;
}
Cygwin下不能正常使用Windows下的system命令,所以不能够这样用。
- 不能够正常使用文本文档流入流出的备用方案:
直接将data.cpp a.cpp b.cpp改为重定向的文件输入输出,即用freopen打开文件,duipai文件中就不在添加"<data.txt>a.txt"或是">data.txt"这样的命令后缀,直接运行exe文件即可。