构造数据

引言

做了很多的题,有时候也会有自己出题的冲动,虽然会出题但是不会造数据咋整?!

建议大家在出题前多刷题,见过更多的好题才能出好题!

造题目数据本质上是通过随机数函数生成 随机数据 ,再通过 文件读写 将随机生成的输入数据存入 xx1.in 标准答案的输出数据存入 xx1.out 。xx 为题目名,1 表示第 1 组数据,多组数据依次编号。

构造数据基本操作

  • rand()或梅森旋转算法产生随机的输入数据
  • freopen("输入文件名.in",'w',stdout); 将随机产生的输入数据写入输入样例文件。
  • freopen("输出文件名.out",'w',stdout);将答案写入输出样例文件。
  • 使用rand()函数时需用srand(time(NULL))设置随机种子为时间。

补充:这里也可以使用 ofstream 类声明的变量进行文件写入操作。

一、例题

第一次创建题目时请阅读 菜单下的

  • 数据需要命名规范, 第一组数据 xx1.in 和 xx1.out 第二组 xx2.in 和 xx2.out 等
  • 将数据压缩为不超过 50MB 的 zip 格式压缩包。
  • 需要用到数学公式可参考 LatexKatex 使用时公式两边添加。
  • 需要特判的题目请阅读 Special-Judge

题目描述:

  • 输入两个正整数 A 和 B,输出 A + B 的值。

输入样例

  • 输入两个正整数 A 和 B 。

输出样例

  • 输出 A + B 的值。

数据范围

  • 对于 60% 的数据,A,B106
  • 对于 100% 的数据,A,B1012

二、随机产生输入数据的函数

注意:rand() 函数只能够产生 0~32767 以内的整数。如果需要产生随机程度更好值更大的随机数可以使用梅森旋转法随机数产生的周期为2199371

random_device rd;           //声明随机数变量
mt19937 gen(rd());          //mt19937是伪随机数生成器类,生成随机数
ll brand() {   //获取正态分布随机整数,范围从0到long long最大值
	uniform_int_distribution<long long> dist(0, numeric_limits<long long>::max());
	return dist(gen);
}												
double drand() {//获取平均分布浮点数(注意范围不是0.0-3.0)
	normal_distribution<double> dist(0.0, 3.0); 
	return dist(gen);
}

下面我们主要使用梅森旋转构造的随机数产生函数 brand()产生 0至2631范围内的随机数。

1、随机产生[a..b]范围内的整数

int res = brand() % (b-a+1) + a;

2、随机产生字符

//方法一
char ch = char( brand() % 26 + 'a');
//方法二
string letter="ab…yzAB…YZ01…89";//省略号自行补充
char ch = letter[brand()% 62];//随机大小写和数字

3、随机产生字符串

int len = brand() % 8 + 3; //产生长度为3-10的字符串
string str;
for(int i=1;i<=len;i++) //随机长度为len的仅包含小写字母的字符串
  str += char(brand() % 26 + 'a');

4、随机产生浮点数

//产生带两位小数的浮点数
double f = (brand()% (b - a + 1) + a) / 100.0;

三、构造数据的代码

1、构造一组数据的代码

#include <bits/stdc++.h>
using namespace std;
const int MOD = 1e6;
int main() {
	srand(time(NULL));	//设置随机种子为时间(毫秒)
	
	//随机产生输入数据 a 和 b
	int a = rand() % MOD + 1, b = rand() % MOD + 1;
	
	//注意是"w"和stdout 将输入数据a和b输出到文件 data1.in 中
	freopen("data1.in", "w", stdout);	
	cout << a << " " << b;
  	fclose(stdout);//关闭文件

	//注意是"w"和stdout 将运算结果输出到文件 data1.out 中
	freopen("data1.out", "w", stdout);
	cout << a + b;
	fclose(stdout); //关闭文件
	return 0;
}

2、构造多组数据的代码

构造多组数据的方式需要通过循环且每次循环改变输入和输出文件的名字将 xxxx1.inxxxx2.out 改变为 xxxx2.inxxxx2.out
1.用string类型的 + 来拼接字符串。
2.用to_string(x)函数将整型x转换为字符串。
3.将文件名+数据组数+后缀的方式组合。例如: string path = "data" + to_string(x) + ".in"
4.再利用文件操作freopen()或者其他文件操作函数打开文件并将数据输出到文件内即可。
5.若是freopen()函数需用.c_str()将string转换为char[] 例:freopen(path.c_str(),"w",stdout)

/*----------------------------------------------程序说明-------------------------------------------------------*/
/*
  造数据步骤:
  1.思考要考的东西
  2.思考数据范围(如果一道题有多种解法,而你要考的效率更高,可以思考卡数据)
  3.把标准程序做好.
  4.在work()函数中造数据
 */

/*
  各个函数的作用:
  函数名                 作用                是否需要修改					      注释
  -----------------------------------------------------------------------------------------------------------------
  getPath()   生成文件名                           ✘
  brand()     获取随机整数,范围从0到long long     ✘                 brand()%100+1 可获得[1,100]范围的随机数
  drand()     获取随机浮点数                       ✘		  
  work()      造数据                               ✔
 */

/*----------------------------------------------------正片开始----------------------------------------------------*/
#include <bits/stdc++.h>
#define ll long long
#define ull unsigned long long
using namespace std;
string file(int n, string io);
/*--------------------------------------------题目相关信息------------------------------------------------------*/
string name = "data", in = ".in", out = ".out"; //文件,格式为dataxx.in或dataxx.out 	xx表示数据编号
void work(int z);                               //定义造数据函数
random_device rd;                               //声明随机数变量
mt19937 gen(rd());                              //mt19937是伪随机数生成器类,生成随机数
ofstream rout, wout;                            //文件读写类
//rout将数据输出到输入样例文件
//wout将数据输出到输出样例文件。
/*-------------------------------------------------------------------------------------------------------------*/
string getPath(int n, string io) {              //获取文件名,n为datan+编号(.in或.out)
	string id = to_string(n);                   //将n转化为字符串|---↑这个n
	string filename = name + id + io;
	return filename;
}
ll brand() {                                    //获取正态分布随机正整数,范围从0到long long
	uniform_int_distribution<long long> dist(0, numeric_limits<long long>::max());
	return dist(gen);
}												
double drand() {
	normal_distribution<double> dist(0.0, 3.0); //获取平均分布浮点数
	return dist(gen);
}
int main() {
	for (int z = 1; z <= 10; z++) {             	//这里z<=10中的10是10组输入.in和输出.out数据,可修改
		remove(getPath(z, in).c_str()), rout.open(getPath(z, in), ios_base::app);	//不用修改
		remove(getPath(z, out).c_str()), wout.open(getPath(z, out), ios_base::app);	//不用修改
		work(z);                                    								//不用修改
		cout << "data " << z << " succeed!" << endl;							    //输出第z组数据构造成功
		rout.close(), wout.close();                 							    //不用修改
	}
}
/*-------------------------------------------------------------------------------------------------------------*/

void work(int z) {//这个板子造的是A+B Problem的数据
	ll a, b;
	/*对于60%的数据,1<=a,b<=10000  对于100%的数据,1<=a,b<=10^12*/
	if (z <= 6) a = brand() % 10000 + 1,       b = brand() % 10000 + 1;//这个地方是题目中的对于60%的数据,可以根据题目修改
	else        a = brand() % (ll)5e11 + 5e11, b = brand() % (ll)5e11 + 5e11;//对于另外%40的数据...
	rout << a << " " << b << endl;                                      //输入样例文件
	wout << a + b << endl;                                              //输出样例文件(修改成你的标准代码)
}

四、构造数据的注意事项

1、需要用数组的建议最后几组数据使用最大数据范围,例如题目中有需要有1000个元素,则最后一组数据建议直接将数据元素个数设为1000。
2、出数据的时候对于特殊情况一定要特殊处理,可以特别编写代码构造或者手动构造。
3、多组数据时记得将全局的 数组,vector等容器初始化。
4、如果题目需要特殊判断例如:答案可能不唯一,出选择题或给部分分等,需要使用Special-Judge 可以点击洛谷官方链接自行学习。

五、树与图的数据构造

树与图的数据构造都可以利用BFS算法,实现 O(n) 效率的构造,当然如果数据范围不超过104的情况下也可以选择用O(n2)的时间复杂度造图论数据。

这里给两道题目及其数据构造方式可以自行学习:

T463375 子树统计

T463375 子树统计(造数据的程序)


T492737 图的深度优先遍历


T492737 图的深度优先遍历(造数据的程序)

六、其他

洛谷官方的数据生成器

posted @   KuaiZz  阅读(17)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示