咕咕东的目录管理器
问题描述
咕咕东的雪梨电脑的操作系统在上个月受到宇宙射线的影响,时不时发生故障,他受不了了,想要写一个高效易用零bug的操作系统 —— 这工程量太大了,所以他定了一个小目标,从实现一个目录管理器开始。前些日子,东东的电脑终于因为过度收到宇宙射线的影响而宕机,无法写代码。他的好友TT正忙着在B站看猫片,另一位好友瑞神正忙着打守望先锋。现在只有你能帮助东东!
初始时,咕咕东的硬盘是空的,命令行的当前目录为根目录 root。
目录管理器可以理解为要维护一棵有根树结构,每个目录的儿子必须保持字典序。
现在咕咕东可以在命令行下执行以下表格中描述的命令:
样例输入输出
Input
输入文件包含多组测试数据,第一行输入一个整数表示测试数据的组数 T (T <= 20);
每组测试数据的第一行输入一个整数表示该组测试数据的命令总数 Q (Q <= 1e5);
每组测试数据的 2 ~ Q+1 行为具体的操作 (MKDIR、RM 操作总数不超过 5000);
面对数据范围你要思考的是他们代表的 “命令” 执行的最大可接受复杂度,只有这样你才能知道你需要设计的是怎样复杂度的系统。
Output
每组测试数据的输出结果间需要输出一行空行。注意大小写敏感。
时空限制
Time limit 6000 ms
Memory limit 1048576 kB
Sample input
1
22
MKDIR dira
CD dirb
CD dira
MKDIR a
MKDIR b
MKDIR c
CD …
MKDIR dirb
CD dirb
MKDIR x
CD …
MKDIR dirc
CD dirc
MKDIR y
CD …
SZ
LS
TREE
RM dira
TREE
UNDO
TREE
Sample output
OK
ERR
OK
OK
OK
OK
OK
OK
OK
OK
OK
OK
OK
OK
OK
9
dira
dirb
dirc
root
dira
a
b
c
dirb
x
dirc
y
OK
root
dirb
x
dirc
y
OK
root
dira
a
b
c
dirb
x
dirc
y
解析
对于大型的模拟,首先要有一种整体的构架,结构体或类、函数、封装等等。
对这道题来说,首先明确目录结构体dictionary以及它的各个变量。之后明确它的7个操作,通过函数实现。
看一下这道题的需求,决定我们需要什么数据结构。首先能做到储存多个孩子,vector比较方便。但是题目还需要要求字典序,为了简化这个排序,可能会引入map来映射。因为undo操作的存在,我们需要记录前一条指令,所以建立一个指令的结构体并用一个vector储存前一个指令及指令信息。
对于各个操作,如果成功就将其存入记录指令的容器中。
mkdir创建一个新目录,就是创建一个新的指针指向当前目录。rm删除类似。
cd操作,实际上就是更改当前指针的指向。
对于tree操作,直接遍历会超时,所以,我们的方法是记录前一次tree的结果,如果之后同样的执行,那么直接返回结果(类似记忆化剪枝)。
代码
#include <iostream>
#include <cstring>
#include <string>
#include <map>
#include <vector>
#include <algorithm>
using namespace std;
const string cmd_string[] = { "MKDIR", "RM", "CD", "SZ", "LS", "TREE", "UNDO"};
const int maxn = 100005;
struct Command {
string name, tr;
int type;
void init(string s) {
name = s;
for (int i = 0 ; i < 7 ; i++)
{
if (s == cmd_string[i])
{
type = i;
if (i < 3)
cin >> tr;
break;
}
}
}
}cmd;
struct Directory {
string name;
map<string, int> mp;
int fa, sz;
vector<string> pre, bck;
bool tag;
void init(string s, int p) {
tag = 0;
fa = p;
sz = 1;
name = s;
pre.clear();
bck.clear();
mp.clear();
}
}node[maxn];
int n, cnt, now;
vector<pair<string, pair<int, int> > > v;
void init(){
cnt = 0;
now = 0;
v.clear();
node[0].init("root", -1);
}
void ins(string s, int p){
node[++cnt].init(s, p);
node[p].mp[s] = cnt;
}
void update(int id, int num){
while (id != - 1) {
node[id].tag = 0;
node[id].sz += num;
id = node[id].fa;
}
}
void mkdir(){
if(node[now].mp.count(cmd.tr))
{
cout << "ERR" << endl;
return;
}
ins(cmd.tr, now);
update(now, 1);
v.push_back(make_pair("MKDIR", make_pair(now, cnt)));
cout << "OK" << endl;
}
void rm(){
if(!node[now].mp.count(cmd.tr))
{
cout << "ERR" << endl;
return;
}
int u = node[now].mp[cmd.tr];
update(now, (-1) * node[u].sz);
node[now].mp.erase(node[u].name);
v.push_back(make_pair("RM", make_pair(now, u)));
cout << "OK" << endl;
}
void cd(){
if(cmd.tr == "..")
{
if(node[now].fa == -1)
{
cout << "ERR" << endl;
return;
}
v.push_back(make_pair("CD", make_pair(now, node[now].fa)));
now = node[now].fa;
cout << "OK" << endl;
return;
}
if(!node[now].mp.count(cmd.tr))
{
cout << "ERR" << endl;
return;
}
int u = node[now].mp[cmd.tr];
v.push_back(make_pair("CD", make_pair(now, u)));
now = u;
cout << "OK" << endl;
}
void sz() {
cout << node[now].sz << endl;
}
void undo(){
if(v.size() == 0)
{
cout << "ERR" << endl;
return;
}
auto e = v[v.size() - 1];
v.pop_back();
cout << "OK" << endl;
int tmp = now;
if(e.first == "MKDIR")
{
cmd.name = "RM";
now = e.second.first;
cmd.tr = node[e.second.second].name;
int u = node[now].mp[cmd.tr];
update(now, (-1) * node[u].sz);
node[now].mp.erase(node[u].name);
now = tmp;
}
else if(e.first == "RM")
{
now = e.second.first;
int u = e.second.second;
update(now, node[u].sz);
node[now].mp[node[u].name] = u;
now = tmp;
}
else
now = e.second.first;
}
void ls(){
int t = node[now].mp.size();
auto pos = node[now].mp.begin();
if (t == 0)
{
cout << "EMPTY" << endl;
return;
}
else if(t >= 1 && t <= 10)
{
while (pos != node[now].mp.end())
{
cout << pos->first << endl;
pos++;
}
return;
}
else
{
for(int i = 1 ; i <= 5 ; i++)
{
cout << pos->first << endl;
pos++;
}
cout << "..." << endl;
pos = node[now].mp.end();
for(int i = 1 ; i <= 5 ; i++)
pos--;
for(int i = 1; i <= 5; i++)
{
cout << pos->first << endl;
pos++;
}
}
}
void pushdown(int id);
void pretrack(int id){
node[id].pre.push_back(node[id].name);
if(node[id].sz == 1)
return;
if(node[id].sz <= 10)
{
for(auto i : node[id].mp)
{
if (!node[i.second].tag)
pushdown(i.second);
node[id].pre.insert(node[id].pre.end(), node[i.second].pre.begin(), node[i.second].pre.end());
}
return;
}
int ct = 1;
for(auto i : node[id].mp)
{
if(!node[i.second].tag)
pushdown(i.second);
for(auto j : node[i.second].pre)
{
node[id].pre.push_back(j);
ct++;
if(ct >= 5)
break;
}
if(ct >= 5)
break;
}
}
void bcktrack(int id){
int ct = 0;
auto it = node[id].mp.end();
it--;
for( ; ; it--)
{
int u = it->second;
if(!node[u].tag)
pushdown(u);
for(int i = node[u].bck.size() - 1 ; i >= 0 ; i--)
{
node[id].bck.push_back(node[u].bck[i]);
ct++;
if(ct >= 5)
{
reverse(node[id].bck.begin(), node[id].bck.end());
break;
}
}
if(ct >= 5)
break;
if(it == node[id].mp.begin())
break;
}
}
void pushdown(int id){
node[id].pre.clear();
node[id].bck.clear();
pretrack(id);
if(node[id].sz > 10)
bcktrack(id);
else
node[id].bck = node[id].pre;
node[id].tag = 1;
}
void tree(){
if(!node[now].tag)
pushdown(now);
int m = node[now].sz;
if(m == 1)
cout << "EMPTY" << endl;
else if(m > 1 && m <= 10)
for(int i = 0 ; i < node[now].pre.size() ; i++)
cout << node[now].pre[i] << endl;
else
{
for(int i = 0 ; i < 5 ; i++)
cout << node[now].pre[i] << endl;
cout << "..." << endl;
for(int i = 5 ; i >= 1 ; i--)
cout << node[now].bck[node[now].bck.size() - i] << endl;
}
}
void solve(int T, int Q){
for (int i = 1 ; i <= Q ; ++i)
{
string s;
cin >> s;
cmd.init(s);
int x = cmd.type;
if (x == 0)
mkdir();
else if (x == 1)
rm();
else if (x == 2)
cd();
else if (x == 3)
sz();
else if (x == 4)
ls();
else if (x == 5)
tree();
else if (x == 6)
undo();
}
}
int main()
{
cin.sync_with_stdio(false);
int T, Q;
cin >> T;
while(T--)
{
cin >> Q;
init();
solve(T, Q);
}
}
回顾
这题也是顺着视频里学长的思路,比着助教ppt上的代码写了一遍,感觉自己最不擅长的就是这种复杂的模拟,以后还是要多做…
限时模拟 东东学打牌
题目
最近,东东沉迷于打牌。所以他找到 HRZ、ZJM 等人和他一起打牌。由于人数众多,东东稍微修改了亿下游戏规则:
所有扑克牌只按数字来算大小,忽略花色。
每张扑克牌的大小由一个值表示。A, 2, 3, 4, 5, 6, 7, 8, 9, 10, J, Q, K 分别指代 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13。
每个玩家抽得 5 张扑克牌,组成一手牌!(每种扑克牌的张数是无限的,你不用担心,东东家里有无数副扑克牌)
理所当然地,一手牌是有不同类型,并且有大小之分的。
举个栗子,现在东东的 “一手牌”(记为 α),瑞神的 “一手牌”(记为 β),要么 α > β,要么 α < β,要么 α = β。
那么这两个 “一手牌”,如何进行比较大小呢?首先对于不同类型的一手牌,其值的大小即下面的标号;对于同类型的一手牌,根据组成这手牌的 5 张牌不同,其值不同。下面依次列举了这手牌的形成规则:
大牌:这手牌不符合下面任一个形成规则。如果 α 和 β 都是大牌,那么定义它们的大小为组成这手牌的 5 张牌的大小总和。
对子:5 张牌中有 2 张牌的值相等。如果 α 和 β 都是对子,比较这个 “对子” 的大小,如果 α 和 β 的 “对子” 大小相等,那么比较剩下 3 张牌的总和。
两对:5 张牌中有两个不同的对子。如果 α 和 β 都是两对,先比较双方较大的那个对子,如果相等,再比较双方较小的那个对子,如果还相等,只能比较 5 张牌中的最后那张牌组不成对子的牌。
三个:5 张牌中有 3 张牌的值相等。如果 α 和 β 都是 “三个”,比较这个 “三个” 的大小,如果 α 和 β 的 “三个” 大小相等,那么比较剩下 2 张牌的总和。
三带二:5 张牌中有 3 张牌的值相等,另外 2 张牌值也相等。如果 α 和 β 都是 “三带二”,先比较它们的 “三个” 的大小,如果相等,再比较 “对子” 的大小。
炸弹:5 张牌中有 4 张牌的值相等。如果 α 和 β 都是 “炸弹”,比较 “炸弹” 的大小,如果相等,比较剩下那张牌的大小。
顺子:5 张牌中形成 x, x+1, x+2, x+3, x+4。如果 α 和 β 都是 “顺子”,直接比较两个顺子的最大值。
龙顺:5 张牌分别为 10、J、Q、K、A。
作为一个称职的魔法师,东东得知了全场人手里 5 张牌的情况。他现在要输出一个排行榜。排行榜按照选手们的 “一手牌” 大小进行排序,如果两个选手的牌相等,那么人名字典序小的排在前面。
不料,此时一束宇宙射线扫过,为了躲避宇宙射线,东东慌乱中清空了他脑中的 Cache。请你告诉东东,全场人的排名
样例输入输出
Input
输入包含多组数据。每组输入开头一个整数 n (1 <= n <= 1e5),表明全场共多少人。
随后是 n 行,每行一个字符串 s1 和 s2 (1 <= |s1|,|s2| <= 10), s1 是对应人的名字,s2 是他手里的牌情况。
Output
对于每组测试数据,输出 n 行,即这次全场人的排名。
Sample input
3
DongDong AAA109
ZJM 678910
Hrz 678910
1
2
3
4
Sample output
Hrz
ZJM
DongDong
解析
这道题我的思路是把牌手和牌型合并成一个结构体,包含他的基本信息和牌型。
比较两个人的牌大小,其实就是比较牌型和牌型的大小。牌型大的牌大,牌型相同比大小。这里我选择了用p和tag两个变量来记录牌型大小。如果是最大的牌皇家同花顺,那么p为8,如果是次一等的顺子,那么p为7。同样是顺子,牌的大小不一定相同,顺子中的最大值比另一方最大值大的牌则大,用tag记录最大值作为相同牌型的判断依据。向三带一对这种,我们选择将3张的牌数字乘以100,加上一对的牌的数字,这样就能保证先比较三张的牌,只有相同时才比较对子。各个牌型的处理思路类似,分成8种情况讨论。
经过上述的处理后,按照牌型p>牌大小tag>字符串顺序的顺序对所有人排序输出即可。
代码
#include<iostream>
#include<cstring>
#include<algorithm>
#include<string.h>
using namespace std;
struct player{
char name[10];
int p;
int tag;
bool operator < (const player &x) const
{
if(p == x.p && tag == x.tag)
return strcmp(name, x.name) < 0;
else if(p == x.p)
return tag > x.tag;
else
return p > x.p;
}
}players[10005];
void init(int cnt){
cin >> players[cnt].name;
int a[5];
char s[10];
cin >> s;
int n = strlen(s);
int tag = 0;
for(int i = 0 ; i < n ; i++)
{
if(s[i] == 'A')
a[tag] = 1;
else if(s[i] == 'J')
a[tag] = 11;
else if(s[i] == 'Q')
a[tag] = 12;
else if(s[i] == 'K')
a[tag] = 13;
else if(s[i] == '1')
{
if(s[i + 1] == '0')
{
a[tag] = 10;
i++;
}
else
a[tag] = 1;
}
else
a[tag] = s[i] - '0';
tag++;
}
sort(a, a + 5);
if(a[0] == 1 && a[1] == 10 && a[2] == 11 && a[3] == 12 && a[4] == 13)
{
players[cnt].p = 8;
players[cnt].tag = 0;
}
else if(a[4] == a[3] + 1 && a[3] == a[2] + 1 && a[2] == a[1] + 1 && a[1] == a[0] + 1)
{
players[cnt].p = 7;
players[cnt].tag = a[4];
}
else if(a[0] == a[1] && a[1] == a[2] && a[2] == a[3])
{
players[cnt].p = 6;
players[cnt].tag = a[0] * 100 + a[4];
}
else if(a[1] == a[2] && a[2] == a[3] && a[3] == a[4])
{
players[cnt].p = 6;
players[cnt].tag = a[4] * 100 + a[0];
}
else if(a[0] == a[1] && a[1] == a[2] && a[3] == a[4])
{
players[cnt].p = 5;
players[cnt].tag = a[0] * 100 + a[4];
}
else if(a[0] == a[1] && a[2] == a[3] && a[3] == a[4])
{
players[cnt].p = 5;
players[cnt].tag = a[4] * 100 + a[0];
}
else if(a[0] == a[1] && a[1] == a[2])
{
players[cnt].p = 4;
players[cnt].tag = a[0] * 100 + a[3] + a[4];
}
else if(a[1] == a[2] && a[2] == a[3])
{
players[cnt].p = 4;
players[cnt].tag = a[1] * 100 + a[0] + a[4];
}
else if(a[3] == a[4] && a[2] == a[3])
{
players[cnt].p = 4;
players[cnt].tag = a[2] * 100 + a[0] + a[1];
}
else if(a[0] == a[1] && a[2] == a[3])
{
players[cnt].p = 3;
players[cnt].tag = a[2] * 10000 + a[0] * 100 + a[4];
}
else if(a[0] == a[1] && a[3] == a[4])
{
players[cnt].p = 3;
players[cnt].tag = a[3] * 10000 + a[0] * 100 + a[2];
}
else if(a[1] == a[2] && a[3] == a[4])
{
players[cnt].p = 3;
players[cnt].tag = a[3] * 10000 + a[1] * 100 + a[0];
}
else if(a[0] == a[1])
{
players[cnt].p = 2;
players[cnt].tag = a[1] * 100 + a[2] + a[3] + a[4];
}
else if(a[1] == a[2])
{
players[cnt].p = 2;
players[cnt].tag = a[1] * 100 + a[0] + a[3] + a[4];
}
else if(a[2] == a[3])
{
players[cnt].p = 2;
players[cnt].tag = a[2] * 100 + a[0] + a[1] + a[4];
}
else if(a[3] == a[4])
{
players[cnt].p = 2;
players[cnt].tag = a[3] * 100 + a[0] + a[1] + a[2];
}
else
{
players[cnt].p = 1;
players[cnt].tag = a[3] + a[4] + a[0] + a[1] + a[2];
}
}
int main(){
int n;
cin >> n;
for(int cnt = 0 ; cnt < n ; cnt++)
init(cnt);
sort(players, players + n);
for(int cnt = 0 ; cnt < n ; cnt++)
cout << players[cnt].name << endl;;
}
回顾
这道题我做的时候wa了几次,是一些无关紧要的小错,主要是当时不仔细…