1. 程式人生 > >[刷題]演算法競賽入門經典(第2版) 5-13/UVa822

[刷題]演算法競賽入門經典(第2版) 5-13/UVa822

題意:模擬客服MM,一共有N種話題,每個客服MM支援處理其中的i個(i < N),處理的話題還有優先順序。為了簡化流程方便出題,設每個話題都是每隔m分鐘來諮詢一次。現知道每個話題前來諮詢的時間、間隔、處理此話題所需的時長與一共有多少次諮詢。問多少時間後全部話題處理完成。

程式碼:(Accepted,0.010s)

//UVa822 - Queue and A
//Accepted 0.010s
//#define _XIENAOBAN_
#include<algorithm>
#include<iostream>
#include<vector>
#include<queue>
#include<map> #define MI 2147483647 using namespace std; struct T { int ti; //time for per task queue<int> table; } ttmp; struct P { int id, at, st, n, to[22];//identity, available time, start time of last task, number of topics, topics bool operator< (const P& that) const
{ if (st != that.st) return st < that.st; return id < that.id; } } ptmp; int Tpc, Psnl;//Number of Topics & Personnel int name, num, nt, to, Scenario(0); int main() { #ifdef _XIENAOBAN_ #define gets(T) gets_s(T, 80) freopen("in.txt", "r", stdin); #endif ptmp.at = 0
; while (scanf("%d", &Tpc) != EOF && Tpc != 0) { int time(MI), needtime(0); map<int, T> tpc; for (int i(0);i < Tpc;++i) { scanf("%d%d%d%d%d", &name, &num, &nt, &ttmp.ti, &to); if (time > nt) time = nt; auto& now(tpc[name] = ttmp); for (int i(0);i < num;++i) now.table.push(nt), nt += to; } scanf("%d", &Psnl); vector<P> psnl(Psnl); for (int i(0);i < Psnl;++i) { scanf("%d%d", &ptmp.id, &ptmp.n); for (int j(0);j < ptmp.n;++j) scanf("%d", ptmp.to + j); psnl[i] = ptmp; } while (Tpc) { int jumpt = MI;//Jump time to the earliest possible available time of all the men sort(psnl.begin(), psnl.end()); for (auto& p : psnl) {//For all staff members int pti(MI);//Man's earliest possible available time if (p.at > time) pti = p.at;//Man is busy else { //Man is available for (int i(0);i < p.n;++i) {//For all topics that man can handle auto& t(tpc[p.to[i]]); if (t.table.empty()) continue; //Man find current topic finished if (t.table.front() <= time) { //Man find his topic pti = time + t.ti; if (needtime < pti) needtime = pti; p.st = time; t.table.pop(); if (t.table.empty()) --Tpc; break; } else if (t.table.front() < pti) pti = t.table.front(); //Man find current topic will be available at t.table.front() } p.at = pti; } if (pti < jumpt) jumpt = pti; } time = jumpt; } printf("Scenario %d: All requests are serviced within %d minutes.\n", ++Scenario, needtime); } return 0; }

分析:每分鐘每分鐘的模擬的話就有點慢了。我的做法是:
對每個topic,把它們每次過來詢問的時間放在queue裡,每開始處理一件就pop一件,直到它empty則說明處理完畢。
對每個員工,找出他的下一次“開始空閒”或“可能有事情做”的時間pti。所謂“開始空閒”或“可能有事情做”的時間是指:

  1. 若這人正在處理一個topic,則pti=處理完本topic的時間,這叫“開始空閒”;
  2. 若這人閒著,則給他找活幹,若找到了可處理topic,pti=處理完這個topic的時間,也是“開始空閒”;
  3. 若這人閒著,但發現無活可幹,每個他可以處理的topic都還沒到來,那麼他的pti=最快到來的下一個topic的時間,即只有topic來了他才可能“可能有事情做”。之所以是“可能”,因為每次都要按照“上一次開始幹活的時間與ID”把每個人排序,所以他的活可能被搶,依然是“無事可幹”狀態。
  4. pti初始化時為int的最大值。只有當該員工的每個topic全都處理完的狀態時,pti全程沒有被賦值,於是該員工的下一個空閒時間變成無限大,一定程度上相當於以後的模擬運算就不考慮他了。

找出了每個人的pti,讓時間跳轉到最近的一個pti,進行下一次迴圈(要注意的是time最終跳出迴圈時可能不等於所需時間,所以又定義了個needtime)。

這題最坑的是,udebug的演算法是錯誤的(⊙﹏⊙)。它的資料答案我死活對不上,害的我除錯了好幾天。。。後來去網上找別人的演算法,發現結果和udebug也一大半資料對不上。但是提交後就AC了。(這uva的資料也比較水,udebug上的100個測試資料我運算了蠻慢的,但提交上去就0.010s。不過開心的是我的運算比網上找的那幾個演算法都快。)