对于算法竞赛中,光会写题这是远远不够的,还需要掌握一些重定向和Windows doc命令等,这里就暂谈一些。而在做算法类竞赛的题目的时候,容易想到一个朴素的能保证完全正确的算法,但是会超时。而高效的算法又不能保证完全写对。这时候可以自己写一个朴素的算法、一个数据生成程序和一个文件比较程序进行验证高效算法的正确性,这就是后面所讲到的Windows对拍程序。
你的三连就是我创作的最大动力!
文件系统
对于文件的位置一般有绝对路径和相对路径。
相对路径:以引用文件之网页所在位置为参考基础,而建立出的目录路径。因此,当保存于不同目录的网页引用同一个文件时,所使用的路径将不相同,故称之为相对。
绝对路径:以Web 站点根目录为参考基础的目录路径。之所以称为绝对,意指当所有网页引用同一个文件时,所使用的路径都是一样的。
例如,
C:\Documents\Admin>
"." -- 代表目前所在的目录,相对路径。 如:<a href="./abc">文本</a> 或 <img src="./abc" />
".." -- 代表上一层目录,相对路径。 如:<a href="../abc">文本</a> 或 <img src="../abc" />
"../../" -- 代表的是上一层目录的上一层目录,相对路径。 如:<img src="../../abc" />
"/" -- 代表根目录,绝对路径。 如:<a href="/abc">文本</a> 或 <img src="/abc" />
"D:/abc/" -- 代表根目录,绝对路径。
从这里可见,我们可以使用当前目录".“和父目录”…"来进行灵活的路径操作。
最大的区别其实就是有无起点,实际指向不随当前路径变化,一般来说,Vscode在终端运行的时候需要打“.\”,这一点和cmd有一些区别。
C++文件操作
必须在 C++ 源代码文件中包含头文件 iostream 和 fstream。
数据类型 | 操作 |
---|---|
ifstream | 该数据类型表示输入文件流,用于从文件读取信息。 |
ofstream | 该数据类型表示输出文件流,用于创建文件并向文件写入信息。 |
fstream | 该数据类型通常表示文件流,且同时具有 ofstream 和 ifstream 两种功能,这意味着它可以创建文件,向文件写入信息,从文件读取信息。 |
模式标志 | 描述 |
---|---|
in | 打开文件用于读取。 |
out | 打开文件用于写入。 |
app | 追加模式。所有写入都追加到文件末尾。 |
ate | 文件打开后定位到文件末尾。 |
trunc | 如果该文件已经存在,其内容将在打开文件之前被截断,即把文件长度设为 0。 |
写入数据
ofstream file;
file.open("1.txt",ios::out);
for(int i=0;i<5;i++){
file<<i<<" ";
}
读数据到结构体中
ifstream in("Name.txt", ios::in);
if (!in.is_open()) {
cout <<"文件打开错误!"<< endl;
exit (0);
}
int i=1;
while (!in.eof()) {
in >> l.a[i].name;
l.length++;
i++;
}
重定向操作
freopen("in.txt", "r", stdin);//从文件读入数据,相当于scanf
freopen("CON", "r", stdin);//重定向,让此时不再读入,便于后续操作。
doc命令
所谓doc命令就是windows cmd命令了。
doc命令 | 功能 |
---|---|
dir | 文件列表 |
cd/md/rd | 改变/创建/删除目录 |
type/more | 显示文件内容 |
fc | 比较文件内容 |
attrib | 修改文件属性 |
copy/xcopy | 复制文件 |
del | 删除文件 |
ren | 文件改名 |
echo | 回显 |
exit | 关闭命令行 |
find | 在文件中查找字符串 |
set | 查看/修改环境变量 |
help | 帮助 |
Windows对拍
在Windows下,fc命令提供了比较文件的功能,虽然批处理不如Linux下的bash等强大,但也足以写个自动比较的程序了。
在竞赛过程中一个对拍程序可以帮你排除许多错误,如果担心自己写的正解被一些小数据卡掉,我们通常会写个对拍程序来检查正解的正确性,通过大量数据观察正解与暴力的输出是否相同。我们首先拿出我们写的可能会超时但是可以保证绝对正确的暴力程序,称作bf.exe,然后拿出我们写的待检测的正解,称作std.exe,接着我们写一个随机数据生成程序,用来一次生成一组自制随机数据用来检测输出,称作gen.exe,然后我们来写一个利用windows批处理的对拍程序。在你的程序的根目录下新建一个称作check.bat的文档,用编辑软件打开这个批处理文件,添加如下代码:
@echo off
:loop
gen.exe > data.in
std.exe < data.in > std.out
bf.exe < data.in > bf.out
fc std.out bf.out
if not errorlevel 1 goto loop
pause
goto loop
第一行echo off作用是关闭多余显示,这样可以只让对拍程序显示对拍信息。第二行loop作用是循环(goto语句),一直进行下面的操作。接下来使用数据生成器r(如上就是gen.exe文件,当然可以用cpp来进行写),然后分别执行std和bf语句,通过fc比较。
大于号代表输出重定向,可让运行的程序的输出结果输出在特定的文件中。小于号代表输入重定向,可让运行的程序从特定的文件读取输入信息。第六行fc操作代表对比两个文件,结果会显示在控制台中。第七行代表如果没有拍出错误就再返回第二行loop进行下一次对拍。第八行pause就是c语言中sysem(“pause”)的操作。第九行可以在pause之后进行第二轮对拍。写完了这个批处理程序就可以保存退出运行对拍了。
对于if not errorlevel 1是什么意思呢?事实上就是如果返回码大于等于num fc程序返回0.(0往往代表结束,所以很多情况建议return 0,一般来说,评分程序会在运行后判断返回码,如果非0,那么认为程序非正常退出了。)
这里以一个具体案例为例,以1+2+…+n输出来比较
这是一个随机生成数程序,用来控制n。 rand.cpp,一定要编译运行生成rand.exe
#include<iostream>
#include<cstdlib>
#include<ctime>
int main()
{
int n;
srand((int)time(0)); //调用srand()函数,以系统时间为随机种子
n = 1 + rand()%1000; //随机生成一个1到1000的自然数
printf("%d\n",n); // 输出随机生成的自然数
return 0;
}
暴力法,时间复杂度O(n)std.cpp +std.exe
#include<cstdio>
#include<cstdlib>
int main()
{
int i,n;
long int sum = 0;
scanf("%d",&n);
for(i=1;i<=n;i++)
{
sum += i;
}
printf("%d\n",sum);
return 0;
}
简单方法,时间复杂度O(1) my.cpp+my.exe
#include<cstdio>
#include<cstdlib>
int main()
{
int n;
long int sum = 0;
scanf("%d",&n);
sum = n*(n+1)/2;
printf("%d\n",sum-1);
return 0;
}
Batch语言 test.bat
@echo off
:loop
rand.exe>data.in
std.exe<data.in>std.out
my.exe<data.in>my.out
fc my.out std.out
if not errorlevel 1 goto loop
pause
goto loop
如何和标准解法不一样,那么会出现以下界面。
如果比较正确则一直在循环。
以上就是关于文件这块的内容,其实这也是算法竞赛常用的技巧,通过暴力来判断程序的正确性!