此前写过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
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
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。
对拍的具体过程如下:
#include
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,通常卡掉自己的数据正是一些特殊的情况。
由于我本地是使用的cygwin的g++环境,且已经配好了环境变量,可以直接使用终端来编译代码。也可以用其他方式来生成。
在该目录下新建一个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两个程序的输出格式一定要相同,共同忽略行末空格或都不忽略。
几点补充:
#include
#include
using namespace std;
int main() {
int t = 1;
while (1) {
system("data.exe>data.txt");
system("a.exea.txt" );
system("b.exeb.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文件中就不在添加"a.txt"或是">data.txt"这样的命令后缀,直接运行exe文件即可。