NOIP比賽中如何加速c++的輸入輸出

NOIP比賽中如何加速c++的輸入輸出

在競賽中,遇到大數據時,每每須要更快的讀取方式。因爲比賽中輸出通常規模較小,本文只討論輸入如何加速.
如今咱們生成1000000個隨機數,構成1000*1000的矩陣,而後輸入比較時間(Win 10系統)ios

#include<iostream>
#include<stdlib.h>
#include<ctime>
using namespace std;
int main(){
    srand((unsigned)time(NULL));
    freopen("out1.txt","w",stdout);
    for(int i=1;i<=1000;i++){
        for(int j=1;j<=1000;j++){
            cout<<rand()<<' ';
        }
        cout<<endl;
    }
}

cin的速度

在比賽中,常常出現數據集超大形成 cin TLE的狀況。這時候大部分人(包括原來我也是)認爲這是cin的效率不及scanf的錯c++

準確的說,cin在不優化的狀況下效率是很低的,咱們來測試一下web

#include<iostream>
#include<cstdio>
#include<ctime>
using namespace std;
int a[1005][1005];
int main(){
    freopen("out1.txt","r",stdin);
    double s=clock();
    for(int i=1;i<=1000;i++){
        for(int j=1;j<=1000;j++){
            cin>>a[i][j];
        }
    }
    printf("time used=%.3fs\n",double(clock()-s)/CLOCKS_PER_SEC);
}

cin的速度
能夠看出,cin的用時達到了驚人的0.763s!!!假如運行時間限制爲1s,那麼程序只剩下0.3秒來計算,是極容易TLE的
所以,遇到大數據時儘可能避免用cin
有博客提到:svg

默認的時候,cin與stdin老是保持同步的,也就是說這兩種方法能夠混用,而沒必要擔憂文件指針混亂,同時cout和stdout也同樣,二者混用不會輸出順序錯亂。正由於這個兼容性的特性,致使cin有許多額外的開銷,如何禁用這個特性呢?只需一個語句std::ios::sync_with_stdio(false);,這樣就能夠取消cin與stdin的同步了函數

其實還有一個等價的寫法測試

cin.tie(0);//取消cin的同步
cout.tie(0);//取消cout的同步

咱們來驗證一下:大數據

#include<iostream>
#include<cstdio>
#include<ctime>
using namespace std;
int a[1005][1005];
int main(){
    freopen("out1.txt","r",stdin);
    std::ios::sync_with_stdio(false);//優化
    double s=clock();
    for(int i=1;i<=1000;i++){
        for(int j=1;j<=1000;j++){
            cin>>a[i][j];
        }
    }
    printf("time used=%.3fs\n",double(clock()-s)/CLOCKS_PER_SEC);
}

cin的優化
時間變成了0.173s,相比cin是飛躍性的優化
可是別急着高興,本人親測,在NOIP的評測機上這樣子會爆0
所以,noip比賽中堅定不要寫std::ios::sync_with_stdio(false)
爆0的緣由以下
noip明確要求使用freopen,而freopen是stdio庫中的,既然咱們已經取消了iostream和stdio的同步,這樣會形成文件指針混亂,進而致使RE 優化

scanf的速度

既然noip比賽中堅定不要寫std::ios::sync_with_stdio(false),那麼咱們能夠用scanfui

#include<iostream>
#include<cstdio>
#include<ctime>
using namespace std;
int a[1005][1005];
int main(){
    freopen("out1.txt","r",stdin);
    double s=clock();
    for(int i=1;i<=1000;i++){
        for(int j=1;j<=1000;j++){
            scanf("%d",&a[i][j]);
        }
    }
    printf("time used=%.3fs\n",double(clock()-s)/CLOCKS_PER_SEC);
}

這裏寫圖片描述
時間變成了0.641s,相比無優化的cin仍是較快的spa

手寫快速讀入的速度

咱們知道,getchar的速度是很快的,但它只能讀取單個字符,所以,咱們經過將字符轉爲整型來優化,同理能夠轉成long long
快速讀入的代碼NOIP初賽曾經考過

#include<iostream>
#include<cstdio>
#include<ctime>
using namespace std;
int a[1005][1005];
inline int read(){//很是重要的快速讀入代碼
    int x=0,sign=1;
    char c=getchar();
    while(c>'9'||c<'0'){//判斷符號
        if(c=='-') sign=-1;
        c=getchar();
    }
    while(c>='0'&&c<='9'){//轉換數
        x=x*10+c-'0';
        c=getchar();
    }
    return x*sign;
}
int main(){
    freopen("out1.txt","r",stdin);
    double s=clock();
    for(int i=1;i<=1000;i++){
        for(int j=1;j<=1000;j++){
            a[i][j]=read();
        }
    }
    printf("time used=%.3fs\n",double(clock()-s)/CLOCKS_PER_SEC);
}

運行後的結果以下:
這裏寫圖片描述
如今這個方法只需0.163s,比其餘的方法都快,並且不會在評測機上出現問題,而且也沒有調用許多函數
遇到數據量大的題,儘可能用手寫的快速讀入來讀取

總結

  1. 遇到大數據時儘可能避免用cin
  2. noip比賽中堅定不要寫std::ios::sync_with_stdio(false)來優化cin
  3. 若是是double或輸入格式較複雜用scanf
  4. 遇到數據量大的題,且是long long或int,儘可能用手寫的快速讀入來讀取
相關文章
相關標籤/搜索