假设某校有20间宿舍,宿舍编号101,102,...,120。每间只住一名学生。初始部分宿舍已用。用两个链表(已用宿舍链表和可用宿舍链表)维护宿舍的管理,实现宿舍分配、宿舍交回。
约定已用宿舍链表按宿舍号升序链接。初始可用宿舍链表也按宿舍号升序链接。
宿舍分配从可用宿舍链表中摘取第一间宿舍分配给学生。学生交回的宿舍挂在可用宿舍链表最后。
备注:使用list容器或静态链表。不用考虑宿舍分配和交回不成功的情况。
假设某校有20间宿舍,宿舍编号101,102,...,120。每间只住一名学生。初始部分宿舍已用。用两个链表(已用宿舍链表和可用宿舍链表)维护宿舍的管理,实现宿舍分配、宿舍交回。
约定已用宿舍链表按宿舍号升序链接。初始可用宿舍链表也按宿舍号升序链接。
宿舍分配从可用宿舍链表中摘取第一间宿舍分配给学生。学生交回的宿舍挂在可用宿舍链表最后。
备注:使用list容器或静态链表。不用考虑宿舍分配和交回不成功的情况。
初始宿舍状态,第一行输入n,表示已用宿舍n间
后跟n行数据,每行格式为:宿舍号 学生姓名
操作次数m,后跟m行操作,操作格式如下:
assign 学生 //为学生分配宿舍,从可用宿舍链表头摘取一间宿舍,
//按宿舍号升序挂在已用宿舍链表中。
return 宿舍号 //学生退宿舍,删除已用宿舍链表中对应结点,
//挂在可用宿舍链表尾部。
display_free //输出可用宿舍链表信息。
display_used //输出已用宿舍链表信息。
display_free依次输出当前可用宿舍链表中的宿舍号,具体格式见样例。
display_used依次输出当前已用宿舍链表中的学生和宿舍号,具体格式见样例。
/*
看到这题第一反应:
STL里有list的话,肯定直接用STL啊!自己写想必会麻烦多了!
但是,用list的时候,又出了一些问题
----------------我本来的思路是这样子的:----------------
写一个类 dorm 表示宿舍,有 string 类的元素姓名,和 int 类的元素,数字标号;并且给dorm类重载小于号等等..
然后,再建2个list,存 dorm 类的元素,再按照题目要求写
但是最后,这个思路被我废掉了,因为我遇到了各种各样的问题,比如说:
1. 怎么让list对自定义类型排序
这个其实我倒是查了不少资料,好像重载<即可,但是最后写出来,在DevC上,出了许多不知道怎么解决的问题
2. 怎么找到给定标号的指定宿舍
如果用 class dorm,并非不能处理,但是比较麻烦,不仅写得麻烦,比起我最终采用的方法,在时间效率上也糟糕许多
还有许许多多的麻烦,不一一列举了,总之就是这个思路,我发现需要许多基本的知识,我都不懂,需要一一去查,所以...决定先放一放这个写自定义类型,并且用它来作为list的类型的方法
嗯,先把别的题目都做完,还有机会再来看看这种方法,如果要实现,应该怎么实现
----------------我后来采取的思路:----------------
后来的思路,就,写法上的简洁性和逻辑性上,就比我最初的思路好了不少(这个方法还是向同学请教的),所以说,有时方法很重要啊!~选错了方法,就是要查很多资料,最后发现这个方法没那么容易走通... T^T
这个方法就很巧妙了,我来总结一下为什么可以这么做:
1. 对于空余的宿舍,我们只是需要知道它的标号即可,这个用 1个 list来保存
2.
对于有人住的宿舍,我们要输出的信息比较多,而且含有中文,就势必需要用 char* 后者 string 类来完成,但是毕竟 C++ 的 string 类有很多方便操作字符串的函数,所以还是选 string 类
但是这里有个小细节需要注意(一开始时,我就没有想明白这个问题,所以后来把这部分翻盘重写了一次):
能不能在 assign 分配宿舍以后,直接将它转换为最终输出的那种格式呢?
就是这种:
姓名(宿舍号)这样?
其实是不可以的!!!这个点有点隐蔽,我一开始为了方便输出,也想这么处理,但后来发现绝对不行!
以为你输出时,已用宿舍是按照宿舍号排列,如果直接转为输出的格式,那么就变成了按名字排
你说你去用 substr截取出名字?
可你又知道名字一定是两位?虽然发出来的数据,名字都是2位的,但万一后台的名字,有些人名字是4位呢?
你说你用 string类的 find_first_of来找到宿舍号的第一位?
嗯,那如果宿舍号的范围改动一下,我只保证宿舍号是3位数,从100~999,而不是像这题,最高位一定是1,那用 find_first_of也没用啊!!!
所以,最好的处理方式,就是将这3位放在最前面,在输出时,再用substr函数处理一下
----------------关于这题,更进一步的思考:----------------
后来突然想到一个有意思的问题,如果这道题,我连宿舍号的位数相同都不保证了,比如说,从 1~1000,这样你用 substr,也不一定就是截取3位嘛...那此时该怎么办呢?
我现在想到的就是,还是把宿舍号放前面,名字放后面,来一个循环:
*/
string s; //s = num + name;
int pos;
for (pos = 0; pos <(int)s.size() && isdigit(s[pos]); pos++);
//这样最终得到的pos,就是名字的起始位置了,pos的前一个位置,就是宿舍号的终止位置了
/*
我觉得这题特别巧妙的地方,也就是对串的处理了
另外...
----------------列举一下这题可能用到的相关函数----------------
string::size() //注意返回值为 size_t,严格说来,用前需要强制转换为int,有时不转也不会错,但是最好还是转
string::substr() //截取字串
stringstream::.str()函数 //将stringstream类转化为string类
to_string() //[ http://www.cplusplus.com/reference/string/to_string/ ]
list::remove() //删除list中的指定元素
list::erase() //删除迭代器内的元素值
list::sort() //排序
----------------查阅资料后,觉得应该注意的细节----------------
1. 来自 c++ 字符串流 sstream(常用于格式转换) [ http://blog.csdn.net/xiaogugood/article/details/21447431 ]
在多次转换中重复使用同一个stringstream(而不是每次都创建一个新的对象)对象最大的好处在于效率。stringstream对象的构造和析构函数通常是非常耗费CPU时间的。
//这个在 ACM 里就有体验过了,string 和 stringstream 真的是很慢的,虽然说 STL 好像都或多或少有性能瓶颈
2. stream 的清空,并不是用 clear(),上篇文章说是用clear(),但我亲自测验过了,用clear()没用,而是应该用
ss.str("");
详见:[ http://blog.csdn.net/chenlei0630/article/details/39643887 ]
摘录:
clear() 方法只是重置了stringstream的状态标志,并没有清空数据。如果需要清空数据,可以用s1.str(“”)来实现这个目的。
谨记!不然很容易使你的程序出现错误,并且吃掉你的内存!
*/
//用sstream
#include
#include
#include
#include
#define rep(i, n) for ( int i = 0; i < (n); i++ )
using namespace std;
int n; // num of dorms
int t; // num of commans
void solve ()
{
list free;
list used;
list::iterator it1;
list::iterator it2;
string s;
stringstream ss;
int num;
int first; // if it is the first element to be output
cin >> n;
for (int i = 101; i <= 120; i++) free.push_back(i);
rep(i, n)
{
cin >> s >> num;
free.remove(num);
// ss.clear();
ss.str("");
ss << num;
string tp = ss.str() + s;
// cout << tp << endl;
used.push_back( tp );
}
cin >> t;
rep(i, t)
{
cin >> s;
if ( s[0] == 'a' )
{
cin >> s;
// cout << "why WA?" << s << endl;
num = free.front();
free.pop_front();
ss.str("");
// ss.clear(); //不知道为什么,明明用了 clear() 以后,下一行仍然有输出
// cout << "wrong there? " << ss.str() << endl;
ss << num;
string tp = ss.str() + s;
// cout << tp << endl;
used.push_back( tp );
}
else if ( s[0] == 'r' )
{
cin >> num;
// ss.clear();
ss.str("");
ss << num;
// cout << "wrong there? " << ss.str() << endl;
string tp = ss.str();
for ( it2 = used.begin(); it2 != used.end(); it2++ )
{
if ( (*it2).substr(0, 3) == tp )
{
used.erase(it2);
break;
}
}
free.push_back(num);
}
else if ( s == "display_free" )
{
first = 1;
for ( it1 = free.begin(); it1 != free.end(); it1++ )
{
if ( first ) first = 0;
else cout << "-";
cout << (*it1);
}
cout << endl;
}
else
{
used.sort();
first = 1;
for ( it2 = used.begin(); it2 != used.end(); it2++ )
{
if ( first ) first = 0;
else cout << "-";
cout << (*it2).substr(3) << "(" << (*it2).substr(0, 3) << ")";
}
cout << endl;
}
}
}
int main ()
{
solve();
return 0;
}
//不用 stream,用 to_string 函数:
/*
说明:
学校的oj用不了 C++11的语法特性,所以这个写法,只是理论可行,没真正在oj上判过
查阅过的相关资料:
http://bbs.csdn.net/topics/392033713
https://stackoverflow.com/questions/15569179/to-string-not-declared-in-scope
http://blog.csdn.net/qiqi123i/article/details/53150837
http://blog.csdn.net/qiqi123i/article/details/61912466
*/
#include
#include
#include
#define rep(i, n) for ( int i = 0; i < (n); i++ )
using namespace std;
int n; // num of dorms
int t; // num of commans
void solve ()
{
list free;
list used;
list::iterator it1;
list::iterator it2;
string s;
int num;
int first; // if it is the first element to be output
cin >> n;
for (int i = 101; i <= 120; i++) free.push_back(i);
rep(i, n)
{
cin >> s >> num;
free.remove(num);
string tp = to_string(num) + s;
used.push_back( tp );
}
cin >> t;
rep(i, t)
{
cin >> s;
if ( s[0] == 'a' )
{
cin >> s;
num = free.front();
free.pop_front();
string tp = to_string(num) + s;
used.push_back( tp );
}
else if ( s[0] == 'r' )
{
cin >> num;
string tp = to_string(num);
for ( it2 = used.begin(); it2 != used.end(); it2++ )
{
if ( (*it2).substr(0, 3) == tp )
{
used.erase(it2);
break;
}
}
free.push_back(num);
}
else if ( s == "display_free" )
{
first = 1;
for ( it1 = free.begin(); it1 != free.end(); it1++ )
{
if ( first ) first = 0;
else cout << "-";
cout << (*it1);
}
cout << endl;
}
else
{
used.sort();
first = 1;
for ( it2 = used.begin(); it2 != used.end(); it2++ )
{
if ( first ) first = 0;
else cout << "-";
cout << (*it2).substr(3) << "(" << (*it2).substr(0, 3) << ")";
}
cout << endl;
}
}
}
int main ()
{
solve();
return 0;
}