ACM/ICPC 之 優先級隊列+設置IO緩存區(TSH OJ-Schedule(任務調度))


一個裸的優先級隊列(最大堆)題,但也有其他普通隊列的做法。這道題我做了兩天,結果發現是輸入輸出太過頻繁,一直只能A掉55%的數據,其他都是TLE,如果將輸入輸出的數據放入緩存區,然后滿區輸出,可以將IO時間消耗降到很低。

 

任務調度(Schedule)


 

描述

某高性能計算集群(HPC cluster)采用的任務調度器與眾不同。為簡化起見,假定該集群不支持多任務同時執行,故同一時刻只有單個任務處於執行狀態。初始狀態下,每個任務都由稱作優先級數的一個整數指定優先級,該數值越小優先級越高若優先級數相等,則任務名ASCII字典順序低者優先。此后,CPU等資源總是被優先級數最小的任務占用;每一任務計算完畢,再選取優先級數最小下一任務。不過,這里的任務在計算結束后通常並不立即退出,而是將優先級數加倍(加倍計算所需的時間可以忽略)並繼續參與調度;只有在優先級數不小於2^32時,才真正退出

你的任務是,根據初始優先級設置,按照上述調度原則,預測一批計算任務的執行序列。

輸入

第一行為以空格分隔的兩個整數n和m,n為初始時的任務總數,m為所預測的任務執行序列長度,每行末尾有一個換行符

以下n行分別包含一個整數和一個由不超過8個小寫字母和數字組成的字符串。前者為任務的初始優先級數,后者為任務名。數字和字符串之間以空格分隔

輸出

最多m行,各含一個字符串。按執行次序分別給出執行序列中前m個任務的名稱,若執行序列少於m,那么輸出調度器的任務處理完畢前的所有任務即可。

Example

Input

3 3
1 hello
2 world
10 test

Output

hello
hello
world

限制

0 ≤ n ≤ 4,000,000

0 ≤ m ≤ 2,000,000

0 < 每個任務的初始優先級 < 2^32

不會有重名的任務

時間:2 sec

內存:512 MB


 

 

  解題思路:

    首先是優先級隊列(最大堆),關於該問題的討論,可以參見我第一篇文章 算法手記 之 數據結構(堆)(POJ 2051)

    建堆算法和插入算法在聽過鄧俊輝老師的MOOC后進行了優化,批量建堆操作可以將時間度綜合效率經過下濾優化至O(N),相對第一次接觸堆的時候有了較大的提高,手寫堆得代碼也可以因此變得更為簡潔。詳細算法參加下面的代碼。

    其次是關於快速輸入輸出(FastIO),我在這里用結構體進行封裝,創建對象IO時可以完成構造函數的操作,包括stdin和stdout兩個流向,一個是最大400萬次輸入,一個是最大200萬次輸出,相信這樣可以將輸入輸出此時降至十位甚至個位數,將輸入輸出對時間的消耗降至極低的水平。

    簡單介紹這里使用的一個設置文件緩存區的函數和另一個相似函數:

    設置文件緩沖區函數
      void setbuf(FILE *stream,char *buf);

      void setvbuf(FILE *stream,char *buf,int type,unsigned size);
      這兩個函數將使得打開文件后,用戶可建立自己的文件緩沖區,而不使用fopen()函數打開文件設定的默認緩沖區。  

      對於setbuf()函數,buf指出緩沖區長度,由stdio.h中定義的宏BUFSIZE的值決定,缺省為512字節。當buf為空時,setbuf函數將使的文件I/O不帶緩沖。

      對setvbuf函數,則由malloc函數來分配緩沖區,參數size指明了緩沖區的長度。

    type則表示了緩沖的類型,其值可以取如下值:

      _IOFBF 文件全部緩沖,即緩沖區裝滿后,才能對文件讀寫
      _IOLBF 文件行緩沖,即緩沖區接收到一個換行符時,才能對文件讀寫

      _IONBF 文件不緩沖,此時忽略buf,size的值,直接讀寫文件,不再經過文件緩沖區緩沖

 

  代碼的寫法模仿了一篇博客,在此表示感謝:terence-yang

  具體代碼如下:

  

 1 //優先級隊列+快速輸入輸出(批量)
 2 //Time: 1508Ms Memory: 109488K(No.20)
 3 #include<iostream>
 4 #include<cstdio>
 5 #include<cstring>
 6 using namespace std;
 7 
 8 #define MAX 4000005
 9 #define LCHILD(x) ((x)<<1)
10 #define RCHILD(x) (((x)<<1) + 1)
11 #define PRIOR(A,x,y) (A[x]>A[y]?(x):(y))
12 
13 int n, m;
14 const long long INF = (long long)1 << 32;    //優先級數上限
15 const int SIZE = 1 << 21;        //緩存區大小
16 
17 /*快速輸入輸出緩存區設置*/
18 struct FastIO {
19     char inbuf[SIZE];
20     char outbuf[SIZE];
21     FastIO() {
22         setvbuf(stdin,inbuf,_IOFBF,SIZE);
23         setvbuf(stdout,outbuf,_IOFBF,SIZE);
24     }
25 }IO;
26 
27 struct Task {
28     char word[9];
29     long long v;
30     bool operator > (Task &a){        /*重載為優先級比較符*/
31         return v < a.v || v == a.v && strcmp(word, a.word) < 0;
32     }
33 }task[MAX];
34 
35 /*在parent和child之間找到最高優先級代替parent*/
36 int replacePa(int x)
37 {
38     int pa = x;
39     if (RCHILD(x) <= n)
40         pa = PRIOR(task, x, PRIOR(task, LCHILD(x), RCHILD(x)));
41     else if (LCHILD(x) <= n)
42         pa = PRIOR(task, x, LCHILD(x));
43     return pa;
44 }
45 
46 /*下濾(向下調整堆)*/
47 void percolateDown(int x)
48 {
49     int rp = replacePa(x);
50     while (rp != x) {
51         swap(task[rp], task[x]);
52         x = rp;
53         rp = replacePa(x);
54     }
55 }
56 
57 /*批量建堆(堆積)*/
58 void heapify()
59 {
60     for (int i = n / 2; i >= 1; i--)
61         percolateDown(i);
62 }
63 
64 int main()
65 {
66     scanf("%d%d", &n, &m);
67     for (int i = 1; i <= n; i++)
68         scanf("%lld%s", &task[i].v, task[i].word);
69     heapify();
70 
71     for (int i = 0; n && i < m; i++)
72     {
73         printf("%s\n", task[1].word);
74         task[1].v *= 2;
75         if (task[1].v >= INF)
76             task[1] = task[n--];
77         percolateDown(1);
78     }
79 
80     return 0;
81 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM