HUSTOJ中Special Judge题目的处理方法

目录导航
  1. 1 简介
  2. 2 Special Judge
  3. 3 Special Judge在HUSTOJ中的使用
    1. 例一
    2. 例二

本文介绍了在流行、开源的ACM Online Judge平台——HUSTOJ上创建Special Judge题目的方法,并以两道题目为例,给出了具体的操作过程。

1 简介

随着ACM/ICPC比赛的不断发展,中国大陆地区已经有越来越多的高校参与到此项赛事中。这里这里可以看到2014年ACM/ICPC中国区六大赛区的参赛情况。

HUSTOJ(Google Code地址Github地址)是一款出色的开源项目,由华中科技大学前ACM队员Sempr等同学开发,2008年5月14日首先上线于华中科技大学,目前已有近百家学校、公司使用HUSTOJ进行计算机程序设计竞赛、计算机程序设计日常教学与测验、人才招聘等。

2 Special Judge

通常的ACM题目包括以下几项内容:题目描述(Description)、输入描述(Input)、输出描述(Output)、样例输入(Sample Input)、样例输出(Sample Out),在后台则包括测试输入(Input Data)和测试输出(Output Data)两项。在评测用户提交的程序正确与否时,系统会将样例输入和测试输入重定向作为程序的标准输入,通过判断程序对应的输出是否与期待的输出完全相同,来判断解答是否正确。

对于同一道题目,用户可能使用各种不同的方法来解答,所以对于某些特殊的题目,其结果可能不唯一,但都符合题目要求。此类题目就需要进行特判(Special Judge)。HUSTOJ便提供了特判功能。

这些题目主要有:
1、答案不唯一。见下例一
2、控制精度。题目要求输出精度在某eps之内。见下例二
3、其他。(欢迎留言补充)

3 Special Judge在HUSTOJ中的使用

主要步骤有:

1、在题目后台编辑页面启用该选项,如图1所示。

图1

2、编制data.indata.outspj.cc(或spj.c)。

3、编译出spj,设执行权限,连同2中的三个文件一起上传至服务器。

例一

下面以UPCOJ中的一道题目为例说明SPJ在HUSTOJ中的使用。
题目版权归原平台、作者所有,本文给出示例并不代表原题目使用同样方法进行评测。

给出一个不小于12的正整数$n$,请你输出两个合数,使他们的和等于$n$。

分析题意,可以得出系统判断用户输出是否正确的两个条件是:

  1. 输出的两个数是否均为合数;
  2. 输出的两个数之和是否为$n$。

首先分别制定data.in(测试输入)、data.out(测试输出)如下:

filename: data.in
1
2
3
4
3
12
15
1000
filename: data.out
1
2
3
8 4
9 6
500 500

然后编写spj.cc(特判程序)。HUSTOJ中的spj.cc需要有3个文件名参数传入:测试输入、测试输出、用户输出。
spj的返回值决定着判断结果,成功返回(0)表示AC,其他非零值表示WA。
下面给出一个本题spj.cc的示例代码。

filename: spj.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <stdio.h>
bool is_prime(int x)//判断素数,伪代码
{
if(x是素数)
return true;
else
return false;
}
int main(int argc,char *args[])//主函数
{
FILE * f_in=fopen(args[1],"r");//测试输入
FILE * f_out=fopen(args[2],"r");//测试输出
FILE * f_user=fopen(args[3],"r");//用户输出
int ret=0;//返回值
int T,n,a,b;
fscanf(f_in,"%d",&T);//从输入中读取数据组数T
while(T--)
{
fscanf(f_in,"%d",&n);
fscanf(f_user,"%d%d",&a,&b);
if(a+b!=n || is_prime(a) || is_prime(b))
ret = 1;//Wrong Answer
}
fclose(f_in);
fclose(f_out);
fclose(f_user);
return ret;
}

编制完spj.cc后,将这些文件上传至服务器。

登录服务器以后进入/home/judge/data/[题号]文件夹,执行以下操作:

/home/judge/data/1000
1
2
3
acm@acm:/home/judge/data/1000$ sudo vim spj.cc #Edit the file spj.cc
acm@acm:/home/judge/data/1000$ sudo g++ -o spj spj.cc # gcc -o spj spj.c
acm@acm:/home/judge/data/1000$ sudo chmod +x spj

测试:

/home/judge/data/1000
1
2
3
4
5
6
acm@acm:/home/judge/data/1000$ ./spj data.in data.out data.out
acm@acm:/home/judge/data/1000$ echo $?
0 #Accepted
acm@acm:/home/judge/data/1000$ ./spj data.in data.out data.in
acm@acm:/home/judge/data/1000$ echo $?
1 #Wrong Answer

在本地HUSTOJ测试,通过网页提交,通过。

例二

某题目要求经过一定复杂计算后输出一个实数结果,精度要求控制在$10^{-4}$内。
分析题意,可知spj需要判断测试输出$a$与用户输出$x$之差是否在eps之内。
spj.cc 如下:

filename: spj.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <stdio.h>
const double eps = 1e-4;
int main(int argc,char *args[])//主函数
{
FILE * f_in=fopen(args[1],"r");//测试输入
FILE * f_out=fopen(args[2],"r");//测试输出
FILE * f_user=fopen(args[3],"r");//用户输出
int ret=0;//返回值
int T;
double a,x;
fscanf(f_in,"%d",&T);//从输入中读取数据组数T
while(T--)
{
fscanf(f_out,"%lf",&a);
fscanf(f_user,"%lf",&x);
if(fabs(a-x)>eps)
ret = 1;//Wrong Answer
}
fclose(f_in);
fclose(f_out);
fclose(f_user);
return ret;
}