如何食用交互题-入门

有时你会在编程比赛里遇到交互题(包括CF)

在这种问题中,输入的数据可能不是预先定好的,但是是为你的解答量身定做的。

评测人写了一个特殊的程序——interactor,这样它的输出对应着你的程序的输入,而你的输出又对映着它的输入。

换句话说,你的程序和 interactor 交换数据,而我的输出基于程序间的“历史交流记录”。

一般人为检验交互题的解答会远远难于常题,因为参与者要在检验过程中扮演 interactor 的角色。

 

一般 oi 场上的交互题都是使用 Grader 交互 和 stdio 交互。

stdio


省流:正常输出输入,当成传统题做即可,但是注意每次输出后要刷新缓存,用 fflush(stdout) 即可,注意输出时有没有换行。

 

对于这类题目,选手只需像往常一样将询问写到标准输出,刷新输出缓冲 后从标准输入读取结果。

选手程序刷新输出缓冲后,通过管道连接它的测评程序(称为交互器)才能立刻接收到这些数据。

因为如果你输出了一些数据,这些数据可能被放置于内部缓存区里,而且或许没有被直接传输给 interactor。

为了避免这种情况的发生,你需要每次输出时用一种特殊的清除缓存操作。

你可以使用如下语句来清空缓冲区:

- 对于 C/C++:fflush(stdout);
- 对于 C++:std::cout << std::flush;
- 对于 Java:System.out.flush();
- 对于 Python:stdout.flush();
- 对于 Pascal:flush(output);
- 对于其他语言,请自行查阅对应语言的帮助文档。

特别的,对于 C++ 语言,在输出换行时如果你使用 `std::endl` 而不是 '\n',也可以自动刷新缓冲区。

 

交互题的输入输出远远小于其他题——尽量用 scanf/printf 代替 cin/cout。

 

IO 交互板子

#include <bits/stdc++.h>
using namespace std;

int L=1, R=1000000000, x;
int main()
{
	while (L<=R)
	{
		int mid=L+R>>1;
		
		printf("%d\n", mid), fflush(stdout);
		scanf("%d", &x);
	
		if (x==0)
		{
			printf("%d\n", mid), fflush(stdout);
			break;
		}
		else if (x==1) R=mid-1;
		else L=mid+1;
	} 
	return 0;
}

  

Grader


题目会给你几个函数接口,一般作为询问的方式。出题人会写一个 grader.cpp 里面就包含了这几个函数。

调用 grader 里面的函数的方法是:加上题目给的头文件/在前面声明要调用的函数(洛谷上用)。

而你要实现一个函数来完成出题人的问题(没有主程序),grader 中有主程序,也就是你完成的是 grader 中的一个函数。

 

Grader 交互板子

题目会给一个 grader,可以在调试中发挥作用(后文会讲到)。

 

洛谷提交方法


洛谷的交互是用 extern,extern 可以置于变量或者函数前,以标示变量或者函数的定义在别的文件中,提示编译器遇到此变量和函数时在其他模块中寻找其定义。

简单来说就是这个函数在 grader 中被 extern 定义过,可以使用 grader 中的这个函数。而你实现的这个函数也加上的 extern 是因为 grader 也要调用这个函数。

当它与 "C" 一起连用时,如: extern "C" void fun(int a, int b),则告诉编译器在编译 fun 这个函数名时按着 C 的规则去翻译相应的函数名而不是 C++ 的

C++ 的规则在翻译这个函数名时会把 fun 这个名字变得面目全非,可能是 fun@aBc_int_int#%$ 也可能是别的,这要看编译器的 "脾气" 了(不同的编译器采用的方法不一样)

为什么这么做呢,因为C++支持函数的重载。

 

板子的代码:

#include <bits/stdc++.h>
using namespace std;

extern "C" int Seniorious(int x);
extern "C" int Chtholly(int n, int c)
{
	int L=1, R=n;
	while (L<=R)
	{
		int mid=L+R>>1, ret=Seniorious(mid);
		
		if (ret==0) return mid;
		else if (ret==1) R=mid-1;
		else L=mid+1;
	}
}

 

请特别注意:

1.你的答案应该作为函数的返回值给出,你不需要,也不应该向标准输出输出任何内容,否则将无法获得分数。

2.题目提供的交互库可能仅供测试样例使用,实际评测时的交互库此交互库不同。

 

正式赛场提交方法


正式赛场上一般是申明头文件就可以实现

例如本题:https://loj.ac/p/3161

代码如下:

#include "explore.h"
#include <bits/stdc++.h>
using namespace std;

void explore(int N, int M) {
	//在此处正常写代码,完成你需要实现的函数即可
	//可以正常调用题目中提供的函数进行交互,如 modify(), query() 等等 
}

  

调试的方法


下文中,code.cpp 就是指你的实现代码。

正常来说在 dev 内是无法直接运行 grader.cpp,code.cpp 来得到 .exe 文件的,需要用命令提示符进行操作。

 

Step.1 添加环境变量

编译 grader.cpp 和 code.cpp 的原理就是,用命令提示符直接通过 g++ 编译器编译,绕过 dev 的编译处理。

想要调用 g++,必须确保编译文件和 g++ 在同一目录,不过这样不方便调试,可以通过添加环境变量解决。

这样无论编译文件在哪,都能直接调用 g++,你可以理解为添加了环境变量后,g++ 和编译文件始终在同一目录(相当于对系统进行了某种神秘操作)。

 

1)复制 /bin 目录的地址

g++ 一般在编译器的 /bin 目录内,可以自己找一下(直接右键 devc++,然后点打开文件所在目录,去里面自己找一下),然后复制地址(右键地址栏那里就可以复制)

如下:C:\Program Files (x86)\Dev-Cpp\MinGW32\bin

image

 

 2)右键此电脑,打开属性

image

 

3)点高级系统设置

image

 

4)在系统属性选项里,点击右下角的“环境变量”选项。

image

 

5)找到path选项 ,点击“编辑”按钮。

image

 

6)将刚才复制的路径加入上或下的“path”选项。

image

 

7)保存编辑,然后按下 WIN+R ,输入 cmd 打开控制台。输入 "g++ -v",如果看到如图所示的提示,说明已经安装成功了。

image

 

Step2.编译文件 & 调试

1)

把 grader.cpp 和 code.cpp 放到同一目录内,然后复制该目录。

开 cmd(在开始菜单,windows 系统内可以找到),切换到该目录(使用 cd 目录... 即可)

image

 

特别的,如果目标路径与当前路径(当前路径会显示在 cmd 每行的开头)的盘符不同,需要先输入 X: 切换盘符,然后输入 cd 路径,其中 X 表示目标路径的盘符。

例如上图中,打开 cmd 时当前路径为 C:\Users\HP,我试图切换至 D:\Fusu\cpp,则需要首先输入 D: 切换盘符,然后输入 cd D:\Fusu\cpp 来更改目录。

 

2)

然后编译,使用编译指令即可。基础指令:

g++ grader.cpp code.cpp -o code.exe

开 O2 与 c++11:

g++ grader.cpp code.cpp -o code.exe -O2 -std=c++11

  

3)

编译出来后,就可以调试了。

在 cmd 里输入可执行文件名,就可以调试该文件。如:

code.exe

image

就可以了。

 

posted @ 2025-10-21 17:56  cn是大帅哥886  阅读(11)  评论(0)    收藏  举报