week9-作业&限时模拟

咕咕东的目录管理器

问题描述

咕咕东的雪梨电脑的操作系统在上个月受到宇宙射线的影响,时不时发生故障,他受不了了,想要写一个高效易用零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了几次,是一些无关紧要的小错,主要是当时不仔细…

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值