算法竞赛常见优化测试 (C++)

本贴最后更新于 1926 天前,其中的信息可能已经时移世改

本文整理并测试、验证了算法竞赛(包括但不限于 NOIP/NOI/ACM/IOI 等)中常用的 C++ 优化技巧。

测试代码可在 OI-share 中浏览:Gitee Github

测试基于 Linux 系统,发行版为 Ubuntu 18.04,内核版本 4.15.0-54,CPU i5-7500,内存 8G。

输入输出

据传输入输出是个容易超时的东东?(以下所有测试基于 NOIP 规则,打开特定输入输出文件)

输入

int

测试内容

读入 n 和 n 个整数,计算其总哈希并输出。(在本次测试中,定义 hash 为求和并自然溢出)

测试数据量

生成十组数据,每组数据n=10 000 000,生成数据文件约 100MB,接近于竞赛中可能出现的最大范围;每个程序每组数据测试 10 次以减小误差,避免偶然性

方案(括号内为编号,偶数不开优化,奇数开优化):

  • scanf 直接读入(0,1)
  • cin 直接读入 (2,3)
  • cin 关闭 sync(std::ios::sync_with_stdio(false);) (4,5)
  • fread() (6,7)
  • mmap() (8,9)

注:6,7,8,9 读入整个文件保存在内存中并采用自定义输入函数解析输入

比较如下。

id # 所有数据总耗时/s(一亿个整数)
0 7.7688905000686646
1 7.4428657531738285
2 26.68755683898926
3 26.47845096588135
4 8.044468140602111
5 7.911801505088807
6 3.538253116607666
7 2.1165251970291137
8 3.392045283317566
9 1.382424759864807

可以发现,在默认情况下,cinscanf 慢 3 到 4 倍,但在执行 ios::sync_with_stdio(false); 后两者相差不大,因此关闭同步后可以放心使用 cin,但是要注意不能混用 cinstdio;在 Linux 系统上,使用 fread()mmap(),将输入先整个保存到内存中再用快读处理是最快的方案,尤其是 mmap(),在 O2 优化的情况下可以达到输入一千万个数据只需要 $0.14$ 秒。

附 mmap 读入代码:

#include<cstdio>
 #include<fcntl.h> 
#include<unistd.h>
#include<sys/types.h>
#include<sys/mman.h>
#include<sys/types.h>
#include<sys/stat.h>
using namespace std;

const int MAXS = 120*1024*1024; //120MB
char* buf;

unsigned int Hash=0;
int len;

void _hash(unsigned int& Hash,unsigned int x){
    Hash+=x;
}

void doit(){
    int x=0;
    char *p=buf;
    while(*p!='\n') *p++;
    while (*p && p-buf<len){
        if ((*p == ' ')||(*p=='\n')||(*p=='\t')){
            _hash(Hash,x);
            x=0;
        }
        else
            x = x * 10 + *p - '0';
        p++;
    }
}

int main(){
    int fd = open("input",O_RDONLY);
    freopen("output","w",stdout);
    len = lseek(fd,0,SEEK_END);
    buf = (char *) mmap(NULL,len,PROT_READ,MAP_PRIVATE,fd,0);
    doit();
    printf("%u\n",Hash);
    return 0;
}

其他代码点此访问

参考资料&&Credit

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...