对拍是一种进行检验或调试的方法,通过对比两个程序的输出来检验程序的正确性。可以将自己程序的输出与其他程序的输出进行对比,从而判断自己的程序是否正确。 对拍过程要多次进行,因此需要通过批处理的方法来实现对拍的自动化。 具体而言,对拍需要一个 数据生成器 和两个要进行输出结果比对的程序。 每运行一次数据生成器都将生成的数据写入输入文件,通过重定向的方法使两个程序读入数据,并将输出写入指定文件,最后利用 Windows 下的 fc 命令比对文件(Linux 下为 diff 命令)来检验程序的正确性。如果发现程序出错,可以直接利用刚刚生成的数据进行调试。

想要实现对拍,所在题目文件夹下至少需要有4个代码文件,结构如下:

文件夹/
├── gen.cpp      # 数据生成器 需要先编译生成可执行文件
├── baoli.cpp    # 暴力解法 需要先编译生成可执行文件
├── youhua.cpp   # 优化解法 需要先编译生成可执行文件
└── duipai.cpp   # 对拍程序

windows 系统的可执行文件后缀名是 .exe ,linux系统的可执行文件没有后缀名。

数据生成器 gen.cpp

#include <iostream>
#include <random> //梅森旋转算法生成器
#include <ctime> //time(0), 获取时间戳,作为随机种子 
using namespace std;

// 生成 [min, max] 范围内的随机整数
long long random_range(long long min, long long max) {
    static mt19937_64 gen(time(0)); // 梅森旋转算法生成器, static 静态,只会执行一次,函数结束后不释放 
    uniform_int_distribution<long long> dis(min, max); // 均匀整数分布
    return dis(gen);
}


int main() {
    // 随机生成长度1-5的数组,不宜太大,太大了会难以分析问题 
    int n = random_range(1,5);
    cout << n << endl;
    for (int i = 0; i < n; i++) {
        cout <<  random_range(-3e9, 3e9) << " ";
    }
    cout << endl;
    
    return 0;
}

对拍程序 duipai.cpp

分两个版本

Linux 版本

#include <cstdio>
#include <cstdlib>

int main() {
  // For Linux
  // 对拍时不开文件输入输出
  // 当然,这段程序也可以改写成批处理的形式
  while (true) {
    system("./gen > test.in");  // 数据生成器将生成数据写入输入文件
    system("./baoli < test.in > a.out");  // 取暴力代码的输出
    system("./youhua < test.in > b.out");  // 获取要提交的程序的输出
    if (system("diff a.out b.out")) {
      // 该行语句比对输入输出
      // diff直接输出不同处
      system("cat test.in");  //显示输入文件内容
      return 0;
      // 该输入数据已经存放在test.in文件中,可以直接利用进行调试
    }
  }
}

Windows 版本

#include <cstdio>
#include <cstdlib>

int main() {
  // For Windows
  // 对拍时不开文件输入输出
  // 当然,这段程序也可以改写成批处理的形式
  while (true) {
    system("gen.exe > test.in");  // 数据生成器将生成数据写入输入文件
    system("baoli.exe < test.in > a.out");  // 获取暴力代码的输出
    system("youhua.exe < test.in > b.out");  // 获取要提交的程序的输出
    if (system("fc a.out b.out")) {
      // 该行语句比对输入输出
      // fc返回0时表示输出一致,否则表示有不同处
      system("type test.in");  //显示输入文件内容
      system("pause");  // 方便查看不同处
      return 0;
      // 该输入数据已经存放在test.in文件中,可以直接利用进行调试
    }
  }
}

要进行对拍的两份代码

以 最大子段和 为例:

最大子段和

注意: 对拍时不能有freopen等输入输出从定向。

暴力代码 baoli.cpp

//最暴力的代码,保证正确性 
#include<iostream>
using namespace std;
const int N = 2E6;
long long a[N];
int main(){
	int n;
	cin >> n;
	for(int i=1;i<=n;i++){
		cin >> a[i];
	}
	long long ans = a[1]; 
	for(int L=1;L<=n;L++){
		for(int R=L;R<=n;R++){
			long long sum = 0;
			for(int i=L;i<=R;i++){
				sum += a[i];
			} 
			ans = max(ans, sum);
		}
	}
	cout << ans;

	return 0;
}

优化代码 youhua.cpp

//将要提交的代码 ,本代码为有错误的代码,主要演示对拍的结果 
#include<iostream>
using namespace std;
const int N = 2e6+5, INF = 0x7fffffffffffffff;
long long a[N],s[N];
int main(){
	long long n, maxn = -INF,minn = INF;
	scanf("%lld", &n);
	for(int i=1; i<=n; i++){
		scanf("%lld", &a[i]);
		s[i] = s[i-1] + a[i];
		maxn = max(maxn, a[i]);
		minn = min(minn, a[i]);
	}
	long long mins=s[1], ans = a[1];
	for(int i=1; i<=n; i++){
		mins = min(mins, s[i]);
		ans = max(ans, s[i]-mins);
	}
	if(ans==0) cout << maxn;
	else if(minn>=0) cout << s[n];
	else  cout << ans;
	
	return 0;
}

0 条评论

目前还没有评论...