日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

OnlineJudge 离线题库采集

發(fā)布時(shí)間:2023/12/31 编程问答 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 OnlineJudge 离线题库采集 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

????過(guò)段時(shí)間要把以前的OJ換掉,我負(fù)責(zé)VirtualJudge的部分。需要用C與PHP寫一個(gè)Linux下的VJudge。

????在此之前,將以前寫給自己學(xué)弟學(xué)妹用的OJ離線題庫(kù)的采集程序改進(jìn)了一下。支持國(guó)內(nèi)一些知名高校的OJ,為之后VJudge的開發(fā)練練手,熟悉下各個(gè)OJ的結(jié)構(gòu),免去以后再在LINUX上進(jìn)行一些繁瑣的測(cè)試。

????題目的采集沒有使用任何OJ的API,直接采取從HTML頁(yè)面采集數(shù)據(jù)并處理的方式。下載HTTP文件使用的是WinINet函數(shù)集,用起來(lái)比CURL還方便。正則表達(dá)式使用的ATL庫(kù)里的regex。題目的儲(chǔ)存使用的文件進(jìn)行儲(chǔ)存。別看一個(gè)OJ就有幾千道題,文件結(jié)構(gòu)訪問的速度卻是相當(dāng)?shù)乜臁R驗(yàn)樽ト〕鰜?lái)的題目有大量的HTML標(biāo)簽,先要全部去掉非常地困難(一些題目有不同的格式與鏈接標(biāo)簽,甚至有一些題目是關(guān)于標(biāo)記語(yǔ)言的題目)。因?yàn)槲椰F(xiàn)在做的是離線的題庫(kù),于是將這些標(biāo)簽保留寫來(lái),利用HTML的方式顯示我采集的題目。


????目前做了六個(gè)OJ:

????1、bnu(北京師范大學(xué)OJ):這個(gè)OJ我覺得是國(guó)內(nèi)用戶體驗(yàn)做得最好的一個(gè)OJ,自己OJ的題目很豐富(含有較多不錯(cuò)的中文),VOJ的功能也完美地融合在自己的OJ中。

????2、hdu(杭州電子科技大學(xué)OJ):擁有國(guó)內(nèi)最強(qiáng)判題機(jī)群,國(guó)內(nèi)各大算法競(jìng)賽都選在杭電OJ舉行。

????3、neu(成都東軟學(xué)院OJ):很多人可能都不知道這OJ,也是國(guó)內(nèi)少數(shù)登錄需要驗(yàn)證碼的奇葩OJ,以至于VOJ想支持它都困難,簡(jiǎn)單題爆多,歡迎來(lái)擼。我母校嘛,必須有,雖然我亞洲區(qū)牌都沒拿到個(gè),學(xué)校最高也就個(gè)銅。補(bǔ)習(xí)班性質(zhì)的比賽嘛,二本學(xué)校的學(xué)生都不想把耍的時(shí)間花在覺得苦逼的事情上,我能拿著塑料堅(jiān)持那么久也是NB了。該OJ即將在今年更換新的系統(tǒng),判題內(nèi)核、數(shù)據(jù)管理、界面、以及VOJ都由我們的老成員完成。希望以后學(xué)校的騷年能取得好成績(jī)--wchrt。

????4、poj(北京大學(xué)OJ):搞ICPC的騷年都知道,國(guó)內(nèi)最為知名的OJ之一。

????5、vijos(高效信息學(xué)在線評(píng)測(cè)系OJ):里面全是中文題哦,小心有大量的小學(xué)生,分分鐘虐爆你的小學(xué)生。

????6、zoj(浙江大學(xué)OJ):國(guó)內(nèi)起步最早的OJ之一,但我基本沒怎么用過(guò)這個(gè)OJ。


????下面根據(jù)各oj分別列出了獲取題目?jī)?nèi)容與標(biāo)題的正則表達(dá)式:

????????ojnum=0;cbox->AddString("bnu");ojurl[ojnum]="http://www.bnuoj.com/bnuoj/problem_show.php?pid=";ojgetstr[ojnum].allcontent="{<div?id=\"showproblem\">(.|\n)*?<div?id=\"one_content_base\">}";ojgetstr[ojnum].title="<div?id=\"showproblem\.*?<h1.*?>{.*?}</h1>";ojgetstr[ojnum].iscode=true;ojgetstr[ojnum].getnum=-1;ojgetstr[ojnum].pnostart=1000;ojnum++;cbox->AddString("hdu");ojurl[ojnum]="http://acm.hdu.edu.cn/showproblem.php?pid=";ojgetstr[ojnum].allcontent="{<h1(.|\n)*?Note</a>}";ojgetstr[ojnum].title="<h1.*?>{.*?}</h1>";ojgetstr[ojnum].iscode=false;ojgetstr[ojnum].getnum=-1;ojgetstr[ojnum].pnostart=1000;ojnum++;cbox->AddString("neu");ojurl[ojnum]="http://acm.nsu.edu.cn/JudgeOnline/problem.php?id=";ojgetstr[ojnum].allcontent="{<div?id=main(.|\n)*?Sample?Output(.|\n)*?BBS(.|\n)*?</a>}";ojgetstr[ojnum].title="<title.*?>{.*?}</title>";//目前不需要把內(nèi)容信息分開,就不正則詳細(xì)的題目?jī)?nèi)容/*ojgetstr[ojnum].tim="Time?Limit:{.*?}&nbsp";ojgetstr[ojnum].mem="Memory?Limit:{.*?}<br>";ojgetstr[ojnum].des=">Description</h2>.*?<div.*?>{.*?}</div>";ojgetstr[ojnum].input=">Input</h2>.*?<div.*?>{.*?</div>.*?}</div>";ojgetstr[ojnum].output=">Output</h2>.*?<div.*?>{.*?}</div>";ojgetstr[ojnum].sinput=">Sample?Input</h2>.*?{<pre>(.|\n)*?</pre>}";ojgetstr[ojnum].soutput=">Sample?Output</h2>.*?{<pre>(.|\n)*?</pre>}";*/ojgetstr[ojnum].iscode=true;ojgetstr[ojnum].getnum=-1;ojgetstr[ojnum].pnostart=1000;ojnum++;cbox->AddString("poj");ojurl[ojnum]="http://poj.org/problem?id=";ojgetstr[ojnum].allcontent="{<div?class=\"ptt\"(.|\n)*?Discuss</a>}";ojgetstr[ojnum].title="<div?class=\"ptt\".*?>{.*?}</div>";ojgetstr[ojnum].iscode=true;ojgetstr[ojnum].getnum=49;//poj最多只允許短時(shí)間訪問49道題ojgetstr[ojnum].pnostart=1000;ojnum++;cbox->AddString("vijos");ojurl[ojnum]="https://vijos.org/p/";ojgetstr[ojnum].allcontent="{<div?class=\"pcontent\">(.|\n)*}<h4";ojgetstr[ojnum].title="<div?class=\"content\">.*?</span>{.*?}<div";ojgetstr[ojnum].iscode=true;ojgetstr[ojnum].getnum=-1;ojgetstr[ojnum].pnostart=1000;ojnum++;cbox->AddString("zoj");ojurl[ojnum]="http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=";ojgetstr[ojnum].allcontent="{<div?id=\"content_body\">(.|\n)*</div>}";ojgetstr[ojnum].title="<div?id=\"content_body\">.*?>.*?>{.*?}</span>";ojgetstr[ojnum].iscode=false;ojgetstr[ojnum].getnum=-1;ojgetstr[ojnum].pnostart=1000;ojnum++;


因?yàn)椴煌腛J網(wǎng)站所使用的編碼格式不同,我使用的是ansi,所以要把一些使用utf-8的網(wǎng)頁(yè)轉(zhuǎn)換為ansi,下面是轉(zhuǎn)換的代碼:

static?void??UTF8toANSI(CString?&strUTF8) {UINT?nLen?=?MultiByteToWideChar(CP_UTF8,NULL,strUTF8,-1,NULL,NULL);WCHAR?*wszBuffer?=?new?WCHAR[nLen+1];nLen?=?MultiByteToWideChar(CP_UTF8,NULL,strUTF8,-1,wszBuffer,nLen);wszBuffer[nLen]?=?0;nLen?=?WideCharToMultiByte(936,NULL,wszBuffer,-1,NULL,NULL,NULL,NULL);CHAR?*szBuffer?=?new?CHAR[nLen+1];nLen?=?WideCharToMultiByte(936,NULL,wszBuffer,-1,szBuffer,nLen,NULL,NULL);szBuffer[nLen]?=?0;strUTF8?=?szBuffer;delete?[]szBuffer;delete?[]wszBuffer; }


????使用WinINet函數(shù)集的CInternetSession與CHttpFile下載HTTP文件,那hdu作為例子

hdu的1001題的地址是:"http://acm.hdu.edu.cn/showproblem.php?pid=1001"

這里的http://acm.hdu.edu.cn/showproblem.php是hdu的題目PHP文件,我們需要以GET的方式請(qǐng)求pid=1001的數(shù)據(jù)。對(duì)于hdu的其他題目,我們只需把pid的值設(shè)置成其他的值即可。


????????//獲取GET方式獲取題目的HTML頁(yè)面CInternetSession?intsess;CHttpFile?*phtfile?=?NULL;phtfile?=?(CHttpFile?*)intsess.OpenURL(url);UINT?nfilelen?=?(UINT)?phtfile->GetLength();CString?strhtml;CString?buffer;UINT?dw=0;while(dw<nfilelen)//將數(shù)據(jù)轉(zhuǎn)入strhtml處理{dw+=phtfile->ReadString(buffer);strhtml+=buffer;dw++;}//使用正則表達(dá)式提取數(shù)需要的內(nèi)容data->all=strhtml;getcontent(ojgetstr->allcontent,strhtml,data->allcontent);//去除題目頁(yè)面的多與信息getcontent(ojgetstr->title,strhtml,data->title);/*getcontent(ojgetstr->tim,strhtml,data->tim);getcontent(ojgetstr->mem,strhtml,data->mem);getcontent(ojgetstr->des,strhtml,data->des);getcontent(ojgetstr->input,strhtml,data->input);getcontent(ojgetstr->output,strhtml,data->output);getcontent(ojgetstr->sinput,strhtml,data->sinput);getcontent(ojgetstr->soutput,strhtml,data->soutput);*/if(ojgetstr->iscode){UTF8toANSI(data->allcontent);UTF8toANSI(data->title);/*UTF8toANSI(data->tim);UTF8toANSI(data->mem);UTF8toANSI(data->des);UTF8toANSI(data->input);UTF8toANSI(data->output);UTF8toANSI(data->sinput);UTF8toANSI(data->soutput);*/}if(data->allcontent.GetLength()<5||data->title.GetLength()<1){return?0;}//將處理后的數(shù)據(jù)寫入到文件中CFile?file;if(!file.Open("c:\\ojdata\\"+data->oj+"\\"+data->id,CFile::modeWrite)){if(!file.Open("c:\\ojdata\\"+data->oj+"\\"+data->id,CFile::modeCreate|CFile::modeWrite)){return?0;}}CArchive?ar(&file,CArchive::store);ar<<data;ar.Close();file.Close();


????因?yàn)槊總€(gè)OJ的題目都有幾千道,不可能每次打開軟件都去遍歷那么幾千個(gè)文件,效率太低而且容易出錯(cuò)。因此我將每個(gè)題目的ID和標(biāo)題都提取出來(lái),放到一個(gè)文件中記錄,用于題目的引索。

引索的結(jié)構(gòu)是:題目數(shù)量、id1、標(biāo)題1、id2、標(biāo)題2、id3...的格式,每個(gè)OJ一個(gè)表。

下面是儲(chǔ)存記錄的代碼,使用序列化儲(chǔ)存:

????????CFile?file;if(!file.Open("c:\\ojdata\\"+oj+"\\pinfo",CFile::modeWrite)){if(!file.Open("c:\\ojdata\\"+oj+"\\pinfo",CFile::modeCreate|CFile::modeWrite)){AfxMessageBox("寫入出錯(cuò)");return?1;}}CArchive?ar(&file,CArchive::store);ar<<that->infonum;for(int?i=0;i<that->infonum;i++){ar<<(&that->problemarr[i]);}ar.Close();file.Close();//統(tǒng)計(jì)題目下載成功與失敗str.Format("SECC:%d??FAIL:%d",that->infonum,totalnum-50-that->infonum);


hdu的:


全是中文題目的OJ,不錯(cuò)不錯(cuò):


水水更健康:

????基本上題目的采集工作到此結(jié)束。以后做VOJ的時(shí)候再將各個(gè)部分正則出來(lái)。

因?yàn)榫W(wǎng)絡(luò)環(huán)境的因素,OJ題目的訪問速度不一定很快,這里可以用開多個(gè)線程進(jìn)行下載,以及優(yōu)化題目的下載和處理,因?yàn)槲铱梢灾苯訏煸谖业姆?wù)器上下載,所以就一條線程下載處理完了。我用的電信50M的寬帶(坑爆,說(shuō)是50M,上行只有不到2M,電信太煎餅了,一個(gè)月169還不包含短信費(fèi),80端口封完喊還推薦我開3000一個(gè)月的商務(wù)寬帶)大概下載一個(gè)OJ的所有題目10多分鐘,我直接6個(gè)OJ一起下載的。不想等待的朋友可以直接在附件下載我采集好的題目包,把它解壓到到C盤即可。


????采集到了題目,怎么看呢?肯定不能直接給人看,一堆標(biāo)記語(yǔ)言煩死了。WINDOWS自帶了瀏覽器控件,直接使用它即可,我使用了兩種方式,一種是對(duì)話框上的HTML控件,可能是我的原因但是這個(gè)控件不穩(wěn)定, 在一些電腦上老加載出錯(cuò)。



????于是我另外用了CDHtmlDialog。這直接是個(gè)HTML的對(duì)話框,每次把題目的本地地址給他后讓其Navigate即可。由于我題目是儲(chǔ)存的一個(gè)problemdata結(jié)構(gòu)體,含有一些其他的信息。打開題目前需要把要顯示的題目提取出來(lái),重新生成一個(gè)HTML文件,然后再讓HTML對(duì)話框打開它。

????題目的顯示過(guò)程:

bool?ProblemList::opensafeproblem(CString?oj,CString?pid) {CFile?file;if(!file.Open("c:\\ojdata\\"+oj+"\\"+pid,CFile::modeRead)){return?false;}CArchive?ar(&file,CArchive::load);problemdata?*data;ar>>data;ar.Close();file.Close();HtmlContent?*contentdlg=new?HtmlContent;if(!contentdlg->setdata(*data)){AfxMessageBox("文件打開失敗");return?false;}contentdlg->Create(IDD_DIALOG_HTML);contentdlg->ShowWindow(SW_SHOW);contentdlg->SetWindowTextA(pid);return?true; }BOOL?HtmlContent::OnInitDialog() {CDHtmlDialog::OnInitDialog();this->SetHostFlags(DOCHOSTUIFLAG_NO3DBORDER?|?DOCHOSTUIFLAG_FLAT_SCROLLBAR);//將題目轉(zhuǎn)化為HTML文件并在本地打開顯示CFile?*f=new?CFile;if(!f->Open("c:\\ojdata\\"+data->oj+"\\"+data->id+".html",CFile::modeCreate|CFile::modeWrite)){AfxMessageBox("打開失敗");this->CloseWindow();}f->Write(data->allcontent,data->allcontent.GetLength());f->Close();this->Navigate("c:\\ojdata\\"+data->oj+"\\"+data->id+".html");return?TRUE;??//?除非將焦點(diǎn)設(shè)置到控件,否則返回?TRUE }

????整個(gè)離線題庫(kù)就是這樣,需要支持其他OJ只要改改正則和題號(hào)即可,對(duì)于一些沒法直接獲取到題目的OJ要做另外的處理,uestc的新OJ就需要另外的方式獲取題目?jī)?nèi)容。

????采集程序源碼

????采集程序

????OJ題庫(kù)下載

轉(zhuǎn)載于:https://blog.51cto.com/wchrt/1606066

總結(jié)

以上是生活随笔為你收集整理的OnlineJudge 离线题库采集的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。