算法競賽入門經典(第二版)-劉汝佳-第五章 C++與STL 習題(13/16)

#說明
本文是我對第五章16道習題的練習總結,建議配合紫書——《算法競賽入門經典(第2版)》閱讀本文。
另外爲了方便做題,我在VOJ上開了一個contest,歡迎一起在上面做:第五章習題contest
如果想直接看某道題,請點開目錄後點開相應的題目!!!

#習題
##習5-1 UVA 1593 代碼對齊(vector)
思路
此題的重點在於讀入數據部分,讀取每一行我用了getline,然後再用stringstream將該行數據分割成字符串vector數組。請讀者自行看代碼體會。
輸出就比較簡單了,不足最大長度的用空格補齊。
代碼

#include <iostream>
#include <sstream>
#include <cstdio>
#include <cstring>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;

const int N = 1000;
const int LEN = 180;

int n;
vector<string> vs[N];
int w[LEN];

int main(void)
{
    n = 0;
    string line, s;
    memset(w, 0, sizeof(w));
    while (getline(cin, line)) {
        stringstream stm(line);
        int i = 0;
        while (stm >> s) {
            w[i] = max(w[i], (int)(s.size()));
            i ++;
            vs[n].push_back(s);
        }
        n ++;
    }

    for (int i = 0; i < n; i ++) {
        int k = vs[i].size();
        for (int j = 0; j < k-1; j ++) {
            cout << vs[i][j];
            for (int r = 0; r <= w[j]-vs[i][j].size(); r ++)
                printf(" ");
        }
        cout << vs[i][k-1] << endl;
    }   
    
    return 0;
}

##習5-2 UVA 1594 Ducci 隊列
思路
沒看出來本題和本章主題C++與STL有什麼聯繫。
思路很簡單,循環1000步,每步檢查是否到終止條件(全0),提前達到終止條件則爲ZERO,否則爲LOOP。
代碼

#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;

const int N = 15;

int n, a[N];

bool is_zero()
{
    for (int i = 0; i < n; i ++) {
        if (a[i]) return false;
    }
    return true;
}

void change()
{
    int tmp = a[0];
    for (int i = 0; i < n-1; i ++)
        a[i] = abs(a[i] - a[i+1]);
    a[n-1] = abs(a[n-1] - tmp);
}

int main(void)
{
    int t;
    cin >> t;
    while (t --) {
        cin >> n;
        for (int i = 0; i < n; i ++)
            scanf("%d", &a[i]);

        int loop = 1001;
        while (loop--) {
            if (is_zero()) break;
            change();
        }

        if (is_zero()) puts("ZERO");
        else puts("LOOP");
    }

    return 0;
}

##習5-3 UVA 10935 卡片遊戲(queue)
思路
看題目描述就能知道是一個隊列,具體細節看代碼吧。
代碼

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <queue>
using namespace std;

int main(void)
{
    int n;
    while (cin >> n && n) {
        queue<int> q;
        for (int i = 1; i <= n; i ++)
            q.push(i);
        printf("Discarded cards:");
        while (q.size() > 2) {
            printf(" %d,", q.front());
            q.pop();
            q.push(q.front());
            q.pop();
        }
        if (q.size() == 2) {
            printf(" %d", q.front());
            q.pop();
        }
        printf("\n");
        printf("Remaining card:");
        printf(" %d\n", q.front());
    }

    return 0;
}

##習5-4 UVA 10763 交流生(排序)
思路
記P(A,B)表示一個想從A校換到B校的學生,數組a[N]和b[N](元素類型爲P)表示所有學生集合(初始內容相同)。
定義兩種比較函數:cmp1表示以元素first爲第一排序依據,second爲第二排序依據,排序順序都是從小到大;cmp2則是以second爲第一依據,first爲第二依據。
a和b分別用cmp1和cmp2排序後,如果a和b的任意第i個元素互相能對應起來,也就是滿足代碼中的條件:
a[i].first == b[i].second && a[i].second == b[i].first
則交換可以進行。
代碼

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

typedef pair<int, int> P;

const int N = 500000;

int n;
P a[N], b[N];

bool cmp1(P p1, P p2)
{
    if (p1.first != p2.first) return p1.first < p2.first;
    return p1.second < p2.second;
}

bool cmp2(P p1, P p2)
{
    if (p1.second != p2.second) return p1.second < p2.second;
    return p1.first < p2.first;
}

int main(void)
{
    while (cin >> n && n) {
        for (int i = 0; i < n; i ++)
            scanf("%d%d", &a[i].first, &a[i].second);
        memcpy(b, a, sizeof(a));

        sort(a, a+n, cmp1);
        sort(b, b+n, cmp2);

        bool flag = true;
        for (int i = 0; i < n; i ++) {
            if (!(a[i].first == b[i].second && a[i].second == b[i].first))
            { flag = false; break;}
        }
        if (flag) puts("YES");
        else puts("NO");
    }

    return 0;
}

##習5-5 UVA 10391 複合詞(查找、set)
思路
有兩種方法可以尋找複合詞:
1、枚舉所有兩個詞的組合,查找是否則詞典中;
2、枚舉所有詞,拆分詞爲s1和s2查找是否都在詞典中。
詞典的規模是120000,顯然第二種時間複雜度低。
儘管思路很清晰,但我還是WA了很多次,最後發現是因爲在打印複合詞之後未break,這可能導致某個複合詞被打印多次。而這個錯誤在示例數據中檢測不出來。

這個題也可以用set,代碼寫起來會簡單一些。
代碼

#include <iostream>
#include <cstdio>
#include <string>
#include <algorithm>
using namespace std;

const int N = 120001;

int n;
string s[N];

int main(void)
{
    n = 0;
    while (cin >> s[n]) n++;
    s[n] = "";      

    string s1, s2;      
    for (int i = 0; i < n; i ++) {
        int m = s[i].size();            
        for (int j = 1; j < m; j ++) {          
            s1 = s[i].substr(0, j);                             
            s2 = s[i].substr(j);                                            
            int k1 = lower_bound(s, s+n, s1) - s;                                       
            int k2 = lower_bound(s, s+n, s2) - s;                                                   
            if (s[k1] == s1 && s[k2] == s2) {
              cout << s[i] << endl;
              break;
            }                                                                          
        }
    }

    return 0;
}

##習5-6 UVA 1595 對稱軸(排序)
思路
與5-4題有相似之處,也是兩個cmp函數分別排序,檢查排序後的數組是否匹配。詳見代碼中cmp函數以匹配的寫法,讀者自行體會。
代碼

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

typedef pair<int, int> P;

const int N = 1000;

int n;
P a[N], b[N];

bool cmp1(P p1, P p2)
{
    if (p1.first != p2.first) return p1.first < p2.first;
    return p1.second < p2.second;
}

bool cmp2(P p1, P p2)
{
    if (p1.first != p2.first) return p1.first > p2.first;
    return p1.second < p2.second;
}

int main(void)
{
    int t;
    cin >> t;
    while (t --) {
        cin >> n;
        for (int i = 0; i < n; i ++)
            scanf("%d%d", &a[i].first, &a[i].second);
        memcpy(b, a, sizeof(a));

        sort(a, a+n, cmp1);
        sort(b, b+n, cmp2);

        int mid2 = a[0].first + a[n-1].first;

        bool flag = true;
        for (int i = 0; i <= n/2; i ++) {
            if (!(a[i].first + b[i].first == mid2 && a[i].second == b[i].second))
            { flag = false; break;}
        }
        if (flag) puts("YES");
        else puts("NO");
    }

    return 0;
}

##習5-7 UVA 12100 打印隊列(queue)
思路
這個題毫無疑問可以用隊列實現,問題是如何判斷某任務是否能夠打印。
根據題意,某任務能夠打印的條件是隊列中沒有更優先的任務。由於優先級只有9個,我們可以定義一個元素個數爲10的數組jobs,jobs[i]表示隊列中優先級爲i的任務的個數。每個任務打印後,其優先級i對應的jobs[i]減1。而優先級爲i的任務能夠打印得條件是對於所有大於i的j,job[j]均爲0。
還有一個小問題是每個任務如何在隊列中表示?優先級信息k肯定是需要的,而且還需要知道任務的id(事實上我們只關心要求的那個id)。所以每個任務的信息可以用id*10+k表示。
代碼

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
using namespace std;

int jobs[10];
queue<int> q;

void init()
{
    memset(jobs, 0, sizeof(jobs));
    while(q.size()) q.pop();
}

bool can_print(int k)
{
    for (int i = k+1; i <= 9; i++) {
        if (jobs[i]) return false;
    }
    return true;
}

int main()
{
    int kase, n, m, k, t;
    scanf("%d", &kase);
    while (kase--) {
        scanf("%d%d", &n, &m);
        init();
        for (int i = 0; i < n; i++) {
            scanf("%d", &k);
            q.push(i*10 + k);
            jobs[k]++;
        }

        t = 0;
        while(q.size()) {
            k = q.front();
            q.pop();
            if (can_print(k%10)) {
                t++;
                jobs[k%10]--;
                if (k/10 == m) break;
            } else
                q.push(k);
        }
        printf("%d\n", t);
    }

    return 0;
}

##習5-8 UVA 230 圖書管理系統(set、map)
思路
本題涉及大量的有序插入和刪除操作,用堆結構的set能夠使時間複雜度最低(O(logN))。
介紹一下代碼中使用的數據結構:
set bks1表示架上圖書集合;
set bks2表示已歸還但未上架的圖書集合;
map< string, string > mp表示標題與作者的映射;
其它內容均體現在代碼中。
代碼

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<set>
#include<map>
using namespace std;

struct Book {
    string name, author;
    bool operator< (Book b) const {
        if (author != b.author) return author < b.author;
        return name < b.name;
    }
};

map<string, string> mp;
set<Book> bks1;
set<Book> bks2;

int main()
{
    string s;
    Book b;
    while (getline(cin, s) && s != "END") {
        int k = s.find('"', 1);
        b.name = s.substr(0, k+1);
        b.author = s.substr(k+5);
        bks1.insert(b);
        mp[b.name] = b.author;
    }

    while (getline(cin, s) && s != "END") {
        if (s[0] == 'S') {
            set<Book>::iterator it1, it2;
            for (it2 = bks2.begin(); it2 != bks2.end(); it2++) {
                it1 = bks1.lower_bound(*it2);
                cout << "Put " << it2->name;
                if (bks1.empty() || it1 == bks1.begin())
                  cout << " first" << endl;
                else
                  cout << " after " << (--it1)->name << endl;
                bks1.insert(*it2);
            }
            bks2.clear();
            cout << "END" << endl;
        } else {
            b.name = s.substr(7);
            b.author = mp[b.name];
            if (s[0] == 'B')
              bks1.erase(b);
            else if (s[0] == 'R')
              bks2.insert(b);
        }
    }

    return 0;
}

##習5-9 UVA 1596 調試(map)
思路
幾個數據結構的說明:
lens表示每個id(即數組)的長度;
ids表示數組名對應的id;
arrs表示每個數組中元素的賦值情況。

對於題意的說明:
1、數組一定是定義過而且只定義過一次的;
2、數組定義行的size部分是一個數字常量,數組中某元素的賦值行則不一定;
3、bug只有兩種情況:一是下標index越界,二是使用未初始化的變量(index和value都可能出現這種情況)
代碼

#include <iostream>
#include <sstream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <map>
#include <vector>
using namespace std;

map<int, int> lens;
map<string, int> ids;
vector<map<int, int> > arrs;

void init_datas()
{
    lens.clear();
    ids.clear();
    arrs.clear();
}

int ID(string s)
{
    if (ids.count(s)) return ids[s];
    map<int, int> mp;
    arrs.push_back(mp);
    return ids[s] = arrs.size()-1;
}

int get_val(string s)
{
    int p = s.find('[');
    if (p == string::npos) return atoi(s.c_str());

    int sid = ID(s.substr(0, p));
    int id = get_val(s.substr(p+1, s.size()-p-2));
    if (id >= 0 && id < lens[sid] && arrs[sid].count(id))
        return arrs[sid][id];
    return -1;
}

bool have_bug(string s)
{
    int k = s.find('=');
    int sid, id, val;
    int p = s.find('[');
    sid = ID(s.substr(0, p));

    if (k == string::npos) {
        stringstream ss(s.substr(p+1));
        ss >> val;
        lens[sid] = val;
        return false;
    }

    id = get_val(s.substr(p+1, k-p-2));
    val = get_val(s.substr(k+1));
    if (id >= 0 && id < lens[sid] && val >= 0) {
        arrs[sid][id] = val;
        return false;
    }
    return true;
}

int main(void)
{
    string s;

    while (cin >> s && s != ".") {
        init_datas();
        int bug = 0, line = 0;
        do {
            line++;
            if (!bug && have_bug(s)) bug = line;
        } while (cin >> s && s != ".");
        printf("%d\n", bug);
    }

    return 0;
}

##習5-10 UVA 1597 在互聯網中搜索(map、set、vector等)
思路
本題直接按string查找會超時,可以將string映射到int後查找。
除了NOT A的查找需要輸出整篇文章,其它查找都是需要輸出文章的對應行。
由於查找時需要忽略大小寫,可以定義兩個變量數組,一個存儲處理前的文章內容,一個存儲處理後的。提取關鍵字有一個小技巧:可以把字符串中所有非英文字母化爲空格。
根據查詢的關鍵字分別處理的過程,可以用到stl中的set_union和set_intersection函數進行求交集和並集。

另外,這題有一個很可笑的問題:
原題中的樣例輸出竟然是錯的,其中的’-‘只有九個,實際上能AC的程序應該是十個。
準確的輸出應該是:----------
代碼

#include<cstdio>
#include<cstring>
#include<iostream>
#include<sstream>
#include<algorithm>
#include<string>
#include<vector>
#include<map>
#include<set>
#include<algorithm>
using namespace std;

const int N = 100;

int n;
vector<string> docs[N];
vector<set<int> > docs_ids[N];

map<string, int> str2id;
vector<string> id2str;

int ID(string s)
{
    if (str2id.count(s)) return str2id[s];
    id2str.push_back(s);
    return str2id[s] = id2str.size()-1;
}

int include_id(vector<set<int> >& ids, int id)
{
    for (int j = 0; j < ids.size(); j++) {
        if (ids[j].count(id)) return j;
    }
    return ids.size();
}

void print_doc(vector<string>& doc)
{
    for (int i = 0; i < doc.size(); i++)
        cout << doc[i] << endl;
}

bool comb(bool a, bool op, bool b)
{
    if (op) return a && b;
    return a || b;
}

int main()
{
    string s, s1, s2;

    cin >> n;
    getchar();
    for (int i = 0; i < n; i++) {
        while (getline(cin, s) && s != "**********") {
          docs[i].push_back(s);
          for (int j = 0; j < s.size(); j++) {
              if (isalpha(s[j])) s[j] = tolower(s[j]);
              else s[j] = ' ';
          }
          stringstream ss(s);
          set<int> st;
          while (ss >> s1)
              st.insert(ID(s1));
          docs_ids[i].push_back(st);
        }
    }

    int m, first;
    cin >> m;
    getchar();
    for (int i = 0; i < m; i++) {
        getline(cin, s);
        first = 1;
        if (s[0] == 'N') { //NOT A
            s = s.substr(4);
            for (int i = 0; i < n; i++) {
                vector<set<int> >& ids = docs_ids[i];
                int id = ID(s);
                if (include_id(ids, id) == ids.size()) {
                    if (!first) printf("----------\n");
                    print_doc(docs[i]);
                    first = 0;
                }
            }
        } else if (s.find(' ') == string::npos) { //key A
            for (int i = 0; i < n; i++) {
                vector<set<int> >& ids = docs_ids[i];
                int id = ID(s);
                int j = include_id(ids, id);
                if (j != ids.size()) {
                    if (!first) printf("----------\n");
                    for (; j < ids.size(); j++) {
                        if (ids[j].count(id))
                          cout << docs[i][j] << endl;
                    }
                    first = 0;
                }
            }
        } else {
            s1 = s.substr(0, s.find(' '));
            s2 = s.substr(s.rfind(' ')+1);
            bool op = (s.find("AND") != string::npos); //A AND B
            for (int i = 0; i < n; i++) {
                vector<set<int> >& ids = docs_ids[i];
                int id1 = ID(s1), id2 = ID(s2);
                int j1 = include_id(ids, id1);
                int j2 = include_id(ids, id2);
                if (comb(j1 != ids.size(), op, j2 != ids.size())) {
                    if (!first) printf("----------\n");
                    for (int j = min(j1, j2); j < ids.size(); j++) {
                        if (ids[j].count(id1) || ids[j].count(id2))
                          cout << docs[i][j] << endl;
                    }
                    first = 0;
                }
            }
        }
        if (first) printf("Sorry, I found nothing.\n");
        printf("==========\n");
    }

    return 0;
}

##習5-11 UVA 12504 更新字典(map)
思路
此題重點有兩個地方:
1、輸入的處理,我的方式詳見代碼;
2、新增、刪除、修改的判斷,使用兩個map分別表示兩個字典,舊字典中鍵值在新字典中找不到表示刪除,找到但修改了表示修改,新字典中鍵值在舊字典中找不到了表示新增。
代碼

#include<cstdio>
#include<cstring>
#include<iostream>
#include<sstream>
#include<map>
#include<vector>
#include<algorithm>
using namespace std;

typedef map<string, string> DICT;
DICT dict1, dict2;

void input_dict(DICT& dict)
{
    dict.clear();
    string s, key, value;
    getline(cin, s);
    for (int i = 0; i < s.size(); i++) {
        if (!isdigit(s[i]) && !isalpha(s[i]))
          s[i] = ' ';
    }
    stringstream ss(s);
    while (ss >> key >> value)
        dict[key] = value;
}

void print_keys(char ch, vector<string> vs)
{
    printf("%c", ch);
    for (int i = 0; i < vs.size(); i++)
      cout << vs[i] << ((i == vs.size()-1) ? '\n' : ',');
}

int main()
{
    int kase;
    cin >> kase;
    getchar();
    while (kase--) {
        input_dict(dict1);
        input_dict(dict2);

        vector<string> add, del, modi;
        DICT::iterator it1, it2;
        for (it1 = dict1.begin(); it1 != dict1.end(); it1++) {
            it2 = dict2.find(it1->first);
            if (it2 == dict2.end()) del.push_back(it1->first);
            else if (it2->second != it1->second) modi.push_back(it1->first);
        }
        for (it2 = dict2.begin(); it2 != dict2.end(); it2++) {
            it1 = dict1.find(it2->first);
            if (it1 == dict1.end()) add.push_back(it2->first);
        }

        if (add.size()) print_keys('+', add);
        if (del.size()) print_keys('-', del);
        if (modi.size()) print_keys('*', modi);
        if (!add.size() && !del.size() && !modi.size()) printf("No changes\n");
        printf("\n");
    }

    return 0;
}

##習5-12 UVA 511 Do You Know the Way to San Jose?(排序、map、sort、unique等)
思路
題目並不難,但細節比較多,排序的依據有很多,比較容易出錯。考差C++和STL也比較全面,比如結構體、構造函數、map、pair、vector、sort、unique等等,代碼規範化會對該題有較大的幫助 。另外注意浮點數大小的比較方法。
我的總體思路是先找出包含該地點的所有地圖,對其area進行排序去重,找出詳細等級爲i對應的area(小於i則報錯,這時也需要輸出最詳細的地圖)。然後將包含該地點同時爲相應area的地圖按照題目描述進行排序,第一個就是所求。
另外注意,書中對該題的描述有一處錯誤:最後一行的“或者包含它的地圖總數超過i”應當改成“或者包含它的不同面積的地圖種數低於i”。
代碼

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <map>
#include <cmath>
using namespace std;

const double EPS = 1e-7;

typedef pair<double, double> P;

struct Map {
    string name;
    double x1, y1, x2, y2, area, d1, d2, d3;

    Map(){}
    Map(string _name, double _x1, double _y1, double _x2,
            double _y2) : name(_name), x1(_x1), y1(_y1), x2(_x2), y2(_y2) {
        if (x1 > x2) swap(x1, x2);
        if (y1 > y2) swap(y1, y2);
        area = (x2 - x1) * (y2 - y1);
    }

    void set_dis(P p)
    {
        double x = p.first, y = p.second;
        double xm = x - (x1 + x2)/2, ym = y - (y1 + y2)/2;
        d1 = xm*xm + ym*ym;
        d2 = (y2 - y1) / (x2 - x1) - 0.75;
        xm = x - x2, ym = y - y1;
        d3 = xm*xm + ym*ym;
    }

    bool contain(P p)
    {
        double x = p.first, y = p.second;
        return x1 <= x && x <= x2 && y1 <= y && y <= y2;
    }

    bool operator < (const Map& b) const {
        if (fabs(d1 - b.d1) > EPS) return d1 < b.d1;
        if (fabs(d2 - b.d2) > EPS) return d2 < b.d2;
        if (fabs(d3 - b.d3) > EPS) return d3 > b.d3;
        return x1 < b.x1;
    }
};

vector<Map> mps;
map<string, P> locas;

void search(string s, int n)
{
    cout << s << " at detail level " << n;
    if (!locas.count(s)) {
        cout << " unknown location\n";
        return;
    }

    P p = locas[s];
    vector<double> area;
    for (int i = 0; i < mps.size(); i++) {
        if (mps[i].contain(p)) {
            area.push_back(mps[i].area);
        }
    }
    if (area.empty()) {
        cout << " no map contains that location\n";
        return;
    }

    sort(area.begin(), area.end(), greater<double>());
    area.erase(unique(area.begin(), area.end()), area.end());
    if (area.size() < n) {
        cout << " no map at that detail level;";
        n = area.size();
    }

    vector<Map> cover;
    for (int i = 0; i < mps.size(); i++) {
        if (mps[i].contain(p) && fabs(mps[i].area - area[n-1]) <= EPS) {
            mps[i].set_dis(p);
            cover.push_back(mps[i]);
        }
    }   
    sort(cover.begin(), cover.end());
    cout << " using " << cover[0].name << endl;
}

int main(void)
{
    string s;
    double x1, x2, y1, y2;

    cin >> s; 
    while (cin >> s && s != "LOCATIONS") {
        cin >> x1 >> y1 >> x2 >> y2;
        mps.push_back(Map(s, x1, y1, x2, y2));
    }

    while (cin >> s && s != "REQUESTS") {
        cin >> x1 >> y1;
        locas[s] = P(x1, y1);
    }   
            
    int n;
    while (cin >> s && s != "END") {
        cin >> n;
        search(s, n);
    }   
    
    return 0;
}

##習5-13 UVA 822 客戶中心(模擬,vector、map)
思路
模擬題,這個題給我坑壞了,先是有兩個判斷條件沒寫好WA了兩次,每次查錯都花好久,但改了還是WA。我用udebug來調,利用上面生成的random數據來測試,始終總是約有20%與標準AC輸出不一樣。然後反覆閱讀自己寫的程序,反覆跟別人的AC程序對比,卻怎麼也找不到原因。後來發現udebug上給的標準AC輸出竟然是錯的!!!因爲其輸出跟別人能AC的程序的運行結果不一樣!再後來我發現其實我的程序沒注意的情況下,修改了一處漏掉的變量初始化部分後,其實提交後已經能夠AC了!!這時候已經花了我將近兩天時間!。。

牢騷完畢,講一下這個題的整體思路:
這是一道並不複雜的流程模擬題,注意看題摳細節,此題關鍵在於安排任務時是以人爲主體還是以請求爲循環主體。
題目講多個人同時選中某個請求時,選出上次處理時間最早的,否則就選出id最小的。乍一看感覺是要以請求爲主體來找人的。但在頭腦中想想會發現很複雜,因爲在找到一個available的人的時候, 還需要跟其他available的人作對比,也就是說先要找出所有available的人, 再從這些人當中選出一個真正available的人來安排給他請求。
解決這個問題的方案就是, 以人爲循環主體來找請求(其實題目裏也有明確的暗示了, 但是說的非常不明確)。按照題目的要求(兩個要求, 自己定義一個比較函數)把存儲人的數組先進行排序,對排序後的人依次找一個請求做就行了。而結束的時機是所有人都不在工作並且所有工作都分配完了。
另外,有一個細節中文翻譯交代的不清楚:不同請求的到來和處理是互相獨立的,也就是說,對某一種請求,允許前一個請求還沒處理完的情況下處理下一個請求(前提是下一個請求已經到來)。

最後,總結一下自己出錯的地方:
1、update()函數中,np不慎寫成了nt,第一次提交報RE,已經懷疑過這個錯誤了,但檢查的時候眼花了沒看到。。
2、忘記了每次主循環開始時Per結構體中tid數組的重新初始化。
3、讀入人的數據時,忘記對新寫入結構體中的變量tproc做初始化,也就是這一行:per[i].tproc = 0;

代碼

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<vector>
#include<map>
using namespace std;

struct Topic {
    int num, t0, t, dt;

    bool proc(int Time)
    {
        if (Time < t0 || num == 0) return false;
        num--;
        t0 += dt;
        return true;
    }

    bool finish(int Time)
    {
        return num == 0 && t0-dt+t <= Time;
    }
};

struct Person {
    int pid, k, last, tproc;
    vector<int> ti;

    bool operator < (const Person& p) const
    {
        if (last != p.last) return last < p.last;
        return pid < p.pid;
    }

    void proc(int t, int Time)
    {
        last = Time;
        tproc = t;
    }

    bool finish(int Time)
    {
        return last + tproc <= Time;
    }
};

int nt, np, Time;
Topic top[20];
Person per[5];

void choose_and_proc(Person& p)
{
    for (int j = 0; j < p.k; j++) {
        int i = p.ti[j];
        if (top[i].proc(Time)) {
            p.proc(top[i].t, Time);
            break;
        }
    }
}

void update()
{
    sort(per, per+np);
    for (int i = 0; i < np; i++) {
        Person& p = per[i];
        if (p.finish(Time)) choose_and_proc(p);
    }
}

bool topics_complete()
{
    //#define DEBUG
#ifdef DEBUG
    printf("Time %d -----\n", Time);
    for (int i = 0; i < nt; i++)
        printf("top%d: num=%d, t0=%d\n", i, top[i].num, top[i].t0);
    printf("-----\n");
    for (int i = 0; i < np; i++)
        printf("per%d: last=%d, tproc=%d\n", i, per[i].last, per[i].tproc);
    printf("==========\n\n");
#endif
    for (int i = 0; i < nt; i++)
        if (!top[i].finish(Time)) return false;
    for (int i = 0; i < np; i++)
        if (!per[i].finish(Time)) return false;
    return true;
}

int main()
{
    //freopen("in.txt", "r", stdin);
    int kase = 0;
    while (scanf("%d", &nt) && nt) {
        int tid;
        map<int, int> index;
        for (int i = 0; i < nt; i++) {
            scanf("%d%d%d%d%d", &tid, &top[i].num,
                    &top[i].t0, &top[i].t, &top[i].dt);
            index[tid] = i;
        }

        scanf("%d", &np);
        for (int i = 0; i < np; i++) {
            scanf("%d%d", &per[i].pid, &per[i].k);
            per[i].ti.clear();
            for (int j = 0; j < per[i].k; j++) {
                scanf("%d", &tid);
                per[i].ti.push_back(index[tid]);
            }
            per[i].last = -1;
            per[i].tproc = 0;
        }
    
        Time = 0;
        do {
            update(); 
            Time++;
        } while (!topics_complete());
        printf("Scenario %d: All requests are serviced within %d minutes.\n", ++kase, Time);   
    }

    return 0;
}

##習5-14 UVA 1598 交易所
思路
以後有時間再做吧。
代碼



##習5-15 UVA 12333 斐波那契的復仇
思路
以後有時間再做吧。
代碼



##習5-16 UVA 212 醫療設備利用
思路
以後有時間再做吧。
代碼



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章