OI造数据以及Lemon评测教程
前言
所谓数据,就是我们对解决某个问题的程序正确与否进行判断的依据。
不同的题目会考虑到时间和空间复杂度,所以需要对数据有严格要求,甚至部分数据只能人为创造。
本教程是基于C/C++和Python的造数据教程,如果不会,请先继续向后看,之后再去学习对应的知识点即可。
并且在后文提供了软件Dev-C++ & Thonny(python集成ide) & Lemon(数据评测软件)的下载地址,Lemon教程在下载处就有,本文在后续会考虑再次更新。
案例一:A+B
最快入门的方式就是做一次题。所以这里会演示一个造数据的全部过程,各位看官请落座。
例:输入两个整数 a,b,输出它们的和,已知 0< a, b<1e+3。
输入样例:1 2 输出样例:3
在造数据前我们需要解决这个问题,得到该问题的标程(标准程序),并命名 std.cpp
#include<iostream>
#include<cstdio>
using namespace std;int main(){int a,b; cin>>a>>b;cout<<a+b<<endl; return 0;
}
那么接下来就开始造数据之旅了,我们需要对标程进行细微的调整,主要是main函数传入参数,开启文件重定向,调整后如下。
#include<iostream>
#include<cstdio>
using namespace std;int main(int argc,char **argv){freopen(argv[1],"r",stdin); // agv[1]这样书写是用于造数剧,如果用于评测这是不对的freopen(argv[2],"w",stdout);int a,b; cin>>a>>b;cout<<a+b<<endl; return 0;
}
对于main函数中参数的解释,命名 t1.cpp
#include<iostream>
#include<cstdio>
using namespace std;/* argc 命令行参数总数argv 命令行参数的字符串指针argv[0] 程序名argv[1+] 用户输入的参数 所以有人也写成 int main(int argc,char *argv[]){}*/
int main(int argc,char **argv){for(int i=0; i<argc; i++){cout<<argv[i]<<" ";} return 0;
}
上述程序 t1.cpp 运行效果:
Microsoft Windows [版本 6.1.7601]
版权所有 (c) 2009 Microsoft Corporation。保留所有权利。C:\Users\Administrator\Desktop\造数据>g++ t1.cpp -o t1C:\Users\Administrator\Desktop\造数据>t1.exe 1 2 3 4 5
t1.exe 1 2 3 4 5 C:\Users\Administrator\Desktop\造数据>
接下来我们就要开始使用Python造数据了,准备好了吗!
关于dos命令演示如下,当我们建立一个1.in文件,并存入数字{ 1 2 },运行该命令就会生成1.out,并向里面存入std.exe执行输入1.in中数据的结果{ 3 }。
Microsoft Windows [版本 6.1.7601]
版权所有 (c) 2009 Microsoft Corporation。保留所有权利。C:\Users\Administrator\Desktop\造数据>g++ t1.cpp -o t1C:\Users\Administrator\Desktop\造数据>t1.exe 1 2 3 4 5
t1.exe 1 2 3 4 5
C:\Users\Administrator\Desktop\造数据>std.exe 1.in 1.out C:\Users\Administrator\Desktop\造数据>
但是这样运行哪有一键Python来的快呢!且看如何使用Python快速进行数据的生成!
C++ 代码,命名 std.cpp -->执行生成 std.exe ,与python最后一行代码对应
import os
import random# 说明:ans=a+b, 0<=a,b<=1000
for i in range(1,11): # [1,11) 以步长为1进行递增with open("%d.in" %i, "w") as fout: # 新建文件i.ina = random.randint(0, 1000) # 生成随机整数,该数范围 [0,1000]b = random.randint(0, 1000) # 生成随机整数,该数范围 [0,1000]fout.write("%d %d" %(a,b)) # 将a b写入文件i.inos.system(r".\std.exe %d.in %d.out" %(i,i)) # dos命令, 注意std.exe,不一定一样,但一定要对应标程
案例一:A+B总结
上述的练习,我们了解了基本过程和原理,接下来做个步骤汇总:
-
建立C/C++标程(命名 std.cpp),并将main函数修改为有参函数,增加文件重定向,并运行生成 .exe 文件
-
建立Python脚本(命名 std.py),注意参数对应,数据量
对于源码的命名其实没有这样的要求,只要程序关键对应即可,这只是让初学者有这样一种格式化的认识罢了!
std.cpp
#include<iostream>
#include<cstdio>
using namespace std;int main(int argc,char **argv){freopen(argv[1],"r",stdin); freopen(argv[2],"w",stdout);int a,b; cin>>a>>b;cout<<a+b<<endl; return 0;
}
std.py
import os
import random# 说明:ans=a+b, 0<=a,b<=1000
for i in range(1,11): # [1,11) 以步长为1进行递增with open("%d.in" %i, "w") as fout: # 新建文件i.ina = random.randint(0, 1000) # 生成随机整数,该数范围 [0,1000]b = random.randint(0, 1000) # 生成随机整数,该数范围 [0,1000]fout.write("%d %d" %(a,b)) # 将a b写入文件i.inos.system(r".\std.exe %d.in %d.out" %(i,i)) # dos命令, 注意std.exe要对应标程
案例二:P1090 [NOIP2004 提高组] 合并果子
题目描述
在一个果园里,多多已经将所有的果子打了下来,而且按果子的不同种类分成了不同的堆。多多决定把所有的果子合成一堆。
每一次合并,多多可以把两堆果子合并到一起,消耗的体力等于两堆果子的重量之和。可以看出,所有的果子经过 n−1 次合并之后, 就只剩下一堆了。多多在合并果子时总共消耗的体力等于每次合并所耗体力之和。
因为还要花大力气把这些果子搬回家,所以多多在合并果子时要尽可能地节省体力。假定每个果子重量都为 1 ,并且已知果子的种类 数和每种果子的数目,你的任务是设计出合并的次序方案,使多多耗费的体力最少,并输出这个最小的体力耗费值。
例如有 3 种果子,数目依次为 1 , 2, 9 。可以先将 1 、 2 堆合并,新堆数目为 3 ,耗费体力为 3 。接着,将新堆与原先的第三堆合并,又得到新的堆,数目为 12 ,耗费体力为 12 。所以多多总共耗费体力 =3+12=15。可以证明 15为最小的体力耗费值。
输入格式
共两行。
第一行是一个整数 n ( 1 ≤ n ≤ 10000 ) (1\leq n\leq 10000) (1≤n≤10000),表示果子的种类数。
第二行包含 n个整数,用空格分隔,第 i 个整数 a i ( 1 ≤ a i ≤ 20000 ) a_i(1\leq a_i\leq 20000) ai(1≤ai≤20000)是第 i 种果子的数目。
输出格式
一个整数,也就是最小的体力耗费值。输入数据保证这个值小于 2 31 2^{31} 231。
输入输出样例
输入 #1
3
1 2 9
输出 #1
15
说明/提示
对于30%的数据,保证有 n ≤ 1000 n \le 1000 n≤1000;
对于50%的数据,保证有 n ≤ 5000 n \le 5000 n≤5000;
对于全部的数据,保证有 n ≤ 10000 n \le 10000 n≤10000。
开始造数据吧!
第一步:出标程
#include<iostream>
#include<queue>
using namespace std;int main(int argc, char**argv){freopen(argv[1], "r", stdin);freopen(argv[2], "w", stdout);int n,a,ans=0;cin>>n;priority_queue<int, vector<int>, greater<int> >q;//升序排序,小顶堆 //priority_queue <int,vector<int>,less<int> >q; //降序排列,大顶堆 for(int i=1; i<=n; i++){cin>>a;q.push(a);}for(int i=1; i<n; i++){a = q.top();//访问队头元素 q.pop(); //弹出队头元素 a += q.top(); q.pop();ans += a;q.push(a); //插入元素到队尾,并排序 }cout<<ans;return 0;
}
第二步:出脚本,注意数据要求范围
import os
import randomfor i in range(1,11):with open("%d.in" %i, "w") as fout:if i<=3:n = random.randint(1, 1000)elif i<=5:n = random.randint(1, 5000)else:n = random.randint(1, 10000)fout.write("%d\n" %n)for j in range(1, n+1):ai = random.randint(1,20000)fout.write("%d " %ai)os.system(r".\std.exe %d.in %d.out" %(i,i))
使用lemon评测
lemon的使用,在以下提供的网址中有明确讲解,这里就不多赘述了。
软件下载
Dev-C++:https://pc.qq.com/detail/16/detail_163136.html
Thonny & Python :http://www.downza.cn/soft/277053.html
Lemon:http://www.pc6.com/softview/SoftView_630536.html
参考资料
【使用python生成信息学奥赛题目测试数据】
【C++造数据 和 对拍】