紫书刷题进行中,题解系列【GitHub|CSDN】
习题5-8 UVA230 Borrowers(44行AC代码)
题目大意
书库有若干本书,每本书有作者和书名两个信息,排列规则:作者字典序小者优先,若相同,则书名字典序小者优先。现有三种操作:
BORROW title
:借书RETURN title
:还书SHELVE
:将目前已还的书按排列规则显示其所在的相对位置(具体格式见原题)
给定一系列操作,处理相应操作,给出相应信息
思路分析
为了记录书本顺序,定义结构体Book
如下,其中重载<
以实现题目要求的排序规则
struct Book {
string aut, tit; // 作者,书名
bool operator < (const Book& b) { // sort排序使用,作者字典序小者优先,若相同,书名优先
return aut < b.aut || (aut == b.aut && tit < b.tit);
}
}book;
定义vector<Book> bk;
存储书本信息,利用sort进行排序后,定义map<string, int> mp;
表示书名->编号,因此每个书名唯一对应一个编号,该编号也表示书的排列顺序。
再定义两个set<int>lib,ret
分别存储目前图书库存和已还图书的编号,由于set自动有序,遇见显示操作时直接顺序遍历ret,按要求输出相应信息即可
注意点
- 注意输出书名时要加双引号
- 注意若已还图书处于第一位,输出
first
等相应信息 - set必须用
iterator--
的方式访问前一个元素,而无法用iterator-1
,因为他是关联容器,不是线性容器
AC代码(C++11,分级sort,set,map)
#include<bits/stdc++.h>
using namespace std;
struct Book {
string aut, tit; // 作者,书名
bool operator < (const Book& b) { // 排序使用,作者字典序小者优先,若相同,书名优先
return aut < b.aut || (aut == b.aut && tit < b.tit);
}
}book;
string s, st, op, tit;
vector<Book> bk; // 存书列表
map<string, int> mp; // 书名对应编号
int main() {
while (getline(cin, s) && s[0] != 'E') {
int i = s.find('"', 1); // 找到第二个引号位置
book.tit = s.substr(1, i-1); // 书名
book.aut = s.substr(i+5); // 作者
bk.push_back(book);
}
sort(bk.begin(), bk.end()); // 排序,作者字典序小优先,若相同,书名字典序小者优先
set<int> lib, ret; // 保存图书库存和还书集合
for (int i = 0; i < bk.size(); i ++) {
mp[bk[i].tit] = i; // 书名对应编号id
lib.insert(i); // 图书库存
}
while (getline(cin, s) && s[0] != 'E') { // 借/还/显示操作处理
if (s[0] == 'S') { // 显示输出
for (auto r : ret) { // 遍历还书集合
auto p = lib.find(r); // 当前书本所在位置
printf("Put \"%s\" ", bk[r].tit.c_str());
printf("%s\n", p == lib.begin() ? "first" : ("after \""+bk[*(--p)].tit+"\"").c_str());
}
puts("END"); ret.clear(); // 清空为下一次准备
continue; // 继续读入
}
op = s.substr(0, 6); // 操作
tit = s.substr(8, s.size()-8-1); // 书名
if (op[0] == 'B') lib.erase(mp[tit]); // 借书,从lib删除
else if (op[0] == 'R') { // 还书
ret.insert(mp[tit]); // 加入还书集合
lib.insert(mp[tit]); // 加入lib集合
}
}
return 0;
}