UVA - 230 Borrowers

/*
法一:
  参考博客: http://blog.csdn.net/shihongliang1993/article/details/73559187
  
   此外,这个blog也是用集合做的,所不同的是,这个博客没用string类型的pair,而是用了两个pair元素组成的结构体:
   以及,下面这个blog的解法虽也为集合,本质上一样,但是没用到C++11的那么多特性,所以更容易理解
   http://www.cnblogs.com/windrises/p/4655736.html

思路:
	* 作者和书名的对应放到map里,可根据书名寻找作者;因为(先按作者,再按标题排序),想到将2个string构造为pair;
	
	* 因为有"No two books have the same title.",想到可以用set,来保存现在书架上可借的书,和已还未归架的书
	
	* 建立书名和作者关联的map,使得可通过书名找到作者
	
收获:
	* 如何在 DevC++中,用C++11标准编译?
	http://blog.csdn.net/qiqi123i/article/details/53150837
	
	* string 的 rfind函数:
	http://blog.csdn.net/dqvega/article/details/6969373
	
	* lower_bound
	http://blog.csdn.net/niushuai666/article/details/6734403
	
	* STL 中的 prev 用法(对随机迭代器进行一次减法)
	http://blog.csdn.net/u013630349/article/details/47105319
	
	* C++中的 auto 用于自动类型推断
	http://blog.csdn.net/huang_xw/article/details/8760403
	
	* make_pair函数
	http://blog.csdn.net/yockie/article/details/6980692
	也可以不用,但是,定义pair类型时,写法会更复杂
	但是也有别的方法,例如此题,可以 typedef pair<string, string> P;
	
	* getline函数, getline(cin, s)常用于读取每行,存入字符串的情况(还可自己设定字符串结束符,不一定非要是回车符)
	http://blog.sina.com.cn/s/blog_60263c1c0101ck25.html
	
	* C++11 的 range-based for loop 语法
	http://blog.csdn.net/foruok/article/details/51593778
	http://en.cppreference.com/w/cpp/language/range-for
	
	* C++ erase函数的几种语法
	http://www.cnblogs.com/ylwn817/articles/1967689.html
	
	
*/




#include <iostream>
#include <set>
#include <unordered_map>
#include <string>
using namespace std;

int main()
{
	string s;
	unordered_map <string, string> books;
	set<pair<string, string>> CBB, TBR; // can be borrowed /  to be returned
	while (getline(cin, s) && s != "END")
	{
		auto pos = s.rfind('"'); 
		auto title = s.substr(0, pos + 1), author = s.substr(pos + 5);
		books[title] = author;
		CBB.insert(make_pair(author, title));
	}
	
	while (getline(cin, s) && s != "END")
	{
		auto order = s.substr(0, 6);
		if (order == "SHELVE")
		{
			for (auto&i : TBR)
			{
				auto pos = CBB.lower_bound(i);
				if (pos == CBB.begin() || CBB.empty()) cout << "Put " << i.second << " first" << endl; //注意不要忘记,可借书的set为空的这种情况
				else cout << "Put " << i.second << " after " << (*prev(pos)).second << endl;
				CBB.insert(i);
			}
			cout << "END" << endl;
			TBR.clear();
		}
		else
		{
			auto title = s.substr(7);
			auto tp = make_pair(books[title], title);
			if (order == "BORROW") CBB.erase(CBB.find(tp));
			else if (order == "RETURN") TBR.insert(tp);
		}		
	}
	return 0;
}

/*
  法二:
  法二是对每个书本,建立结构体,数据成员有作者和状态(1表示可外借,0表示已借出,-1表示已归还但未上架)
  
  之后,再建立书名和书结构体一一对应的map,和放姓名的容器vector
  
  对姓名vector设定一个排序标准,先按作者,再按标题,从小到大排;
  
  对于借书和还书,只是改变该书对应的status,而对于上架操作,则是查找name的依次顺序,如果要放的书是在name中排第一位的,输出 Put+那本书的资料,否则,要输出该书放到哪一本书后面
  
  该方法的好处:
  用了结构体以后,状态的切换就变得相当容易
  且书的上架操作,因为有了vector的自定义排序,便可知道该书是放第一位,还是放其他某书的后面,也就能知道以何种输出方式输出
  
  思路借鉴自:
  http://blog.csdn.net/a197p/article/details/43747539

*/

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

struct Book
{
	string author;
	int status;
	Book(string a = "", int s = 1) : author(a), status(s)
	{
	}
}; 

map<string, Book> Books;
vector<string> Titles;

bool mycmp(const string &a, const string &b)
{
	if(Books[a].author != Books[b].author) return Books[a].author < Books[b].author;
	return a < b; //先比作者,再比标题	
}

int main()
{
	Books.clear();
	Titles.clear();
	string s, x;
	Book tp;
	while (getline(cin, s) && s != "END")
	{
		int pos = (int)s.rfind('"');
		string title = s.substr(0, pos + 1);
		Titles.push_back(title);
		tp.author = s.substr(pos + 5);
		tp.status = 1; //标记状态为可借
		Books[title] = tp; 
	}
	
	sort(Titles.begin(), Titles.end(), mycmp);
	
	while (cin >> s && s != "END")
	{
		if (s == "BORROW")
		{
			getchar();
			getline(cin, x);
			Books[x].status = 0; //表示此书已被借走
		}
		else if (s == "RETURN")
		{
			getchar();
			getline(cin, x);
			Books[x].status = -1; //表示此书已还但未上架
		}
		else if (s == "SHELVE")
		{
			int i, j;
			for (i = 0; i < (int)Titles.size(); i++)
			{
				if (Books[Titles[i]].status == -1)
				{
					for (j = i; j >= 0; j--)
					if (Books[Titles[j]].status == 1)
					{
						break;
					}
					if (j == -1) cout << "Put " << Titles[i] << " first" << endl;
					else cout << "Put " << Titles[i] << " after " << Titles[j] << endl;
					Books[Titles[i]].status = 1; //最初写时,忘了把上架后的书,状态重置为可借,导致找了许久的错误 
				}
				
			}
			cout << "END" << endl;
				
		}
	}
	
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值