week9作业

A 咕咕东的目录管理器

题意
咕咕东的雪梨电脑的操作系统在上个月受到宇宙射线的影响,时不时发生故障,他受不了了,想要写一个高效易用零bug的操作系统 —— 这工程量太大了,所以他定了一个小目标,从实现一个目录管理器开始。前些日子,东东的电脑终于因为过度收到宇宙射线的影响而宕机,无法写代码。他的好友TT正忙着在B站看猫片,另一位好友瑞神正忙着打守望先锋。现在只有你能帮助东东!

初始时,咕咕东的硬盘是空的,命令行的当前目录为根目录 root。

目录管理器可以理解为要维护一棵有根树结构,每个目录的儿子必须保持字典序。

思路
对于每条指令,设置一个结构体,来存储这条指令的各个信息:类型、操作的文件名s(若有)、以及一个容器用来记录这条操作涉及的目录节点。

对于每个节点,设置一个结构体,来存储这个节点的各个信息:当前节点的名字,父节点,子节点的map映射,以该节点为根的子树的大小。以及各种封装的函数。

对于每组数据,新建一个根节点now,然后根据输入的每条指令修改now节点的位置。

由于具有undo操作,需要记录每条成功执行的指令,开设容器cmdlist来存储执行成功的指令。因此在undo时,每次从容器尾部弹出一个命令,对该命令执行撤销操作。

对于TREE指令,要进行前序和后序遍历,但是在未修改的情况下如果多次出现TREE操作,输出的内容是一样的,但却进行了多次的遍历,会导致超时,因此用容器ten来记录符合要求的节点,如果没有修改,则直接输出。如果修改了,则更新后再输出。

代码:

#include <iostream>
#include <cstring>
#include <string>
#include <map>
#include <vector>
#include <algorithm>
using namespace std;
int cnt,T,n,now;
const int maxn=1e5+5;
const string cmd_string[]={"MKDIR","RM","CD","SZ","LS","TREE","UNDO"};

struct command{
	string name,st;
	int sign;
	void init(string t){
		name=t;
		for(int i=0;i<7;i++)
		{
			if(t==cmd_string[i])
			{
				sign=i;
				if(sign<3) cin>>st;
				break;
			}
		}
	}
}cmd;//记录当前操作
struct Dict
{
	string name;
	int sz,parent;
	map<string,int> mp;
	vector<string> pre,bck;
	bool tag;
	void init(string t,int p)
	{
		tag=0;
		name=t;
		parent=p;
		sz=1;
		mp.clear();
		pre.clear();
		bck.clear();
		
	}
}dict[maxn];//目录 

vector<pair<string,pair<int,int> > > v;
void make_dict(string s,int p)
{
	dict[++cnt].init(s,p);
	dict[p].mp[s]=cnt;
}
void update(int id,int num)
{
	while(id!=-1)
	{
		dict[id].sz+=num;
		dict[id].tag=0;
		id=dict[id].parent;
	}
}
//创建
void mkdir()
{
	if(dict[now].mp.count(cmd.st)){//创建目录已存在 
		cout<<"ERR"<<endl;
		return; 
	}
	make_dict(cmd.st,now);
	update(now,1);//更新size
	v.push_back(make_pair("MKDIR",make_pair(now,cnt)));
	cout<<"OK"<<endl; 
}
//删除
void rm()
{
	if(!dict[now].mp.count(cmd.st)){//目录中没有
		cout<<"ERR"<<endl; 
		return;
	}
	int tmp=dict[now].mp[cmd.st];
	update(now,(-1)*dict[tmp].sz);
	dict[now].mp.erase(dict[tmp].name);
	v.push_back(make_pair("RM",make_pair(now,tmp)));
	cout<<"OK"<<endl;
}
//切换
void cd()
{
	if(cmd.st==".."){
		if(dict[now].parent==-1)
		{
			cout<<"ERR"<<endl;
			return;
		}
		v.push_back(make_pair("CD",make_pair(now,dict[now].parent)));
		now = dict[now].parent;	
		cout<<"OK"<<endl;
		return;
	}
	if(!dict[now].mp.count(cmd.st)){
		cout<<"ERR"<<endl;
		return;
	}
	int tmp=dict[now].mp[cmd.st];
	v.push_back(make_pair("CD",make_pair(now,tmp)));
	now=tmp; 
	cout<<"OK"<<endl;
}
//大小
void sz()
{
	cout<<dict[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"){
		now=e.second.first;
		cmd.name="RM";
		cmd.st=dict[e.second.second].name;
		int u=dict[now].mp[cmd.st];
		update(now,-dict[u].sz);
		dict[now].mp.erase(dict[u].name);
		now=tmp;
	}
	else if(e.first=="RM"){
		now=e.second.first;
		int u=e.second.second;
		update(now,dict[u].sz);
		dict[now].mp[dict[u].name]=u;
		now=tmp;
	}
	else now=e.second.first;
	
}
void ls()
{
	if(dict[now].mp.size()==0){
		cout<<"EMPTY"<<endl;
		return;
	}
	if(dict[now].mp.size()>=1 && dict[now].mp.size()<=10)
	{
		auto tmp=dict[now].mp;
		for(auto i=tmp.begin();i!=tmp.end();i++){
			cout<<i->first<<endl;	
		}
	}
	else if (dict[now].mp.size()>10)
	{
		auto u=dict[now].mp.begin();
		for(int i=0;i<5;i++){
			cout<<u->first<<endl;	
			u++;
		}
		cout<<"..."<<endl;
		u=dict[now].mp.end();
		for(int i=0;i<5;i++) u--;
		for(int i=0;i<5;i++){
			cout<<u->first<<endl;
			u++;
		}
	}
}

void pushdown(int p);

void preupdate(int p)
{ 
	dict[p].pre.push_back(dict[p].name);
	if(dict[p].sz==1) return;
	else if(dict[p].sz>1&&dict[p].sz<=10){
		for(auto i:dict[p].mp)
		{
			if(!dict[i.second].tag) pushdown(i.second);
			dict[p].pre.insert(dict[p].pre.end(),dict[i.second].pre.begin(),dict[i.second].pre.end());
		}
		return;
	}
	int t=1;
	for(auto i:dict[p].mp)
	{
		if(!dict[i.second].tag) pushdown(i.second);
		for(auto j:dict[i.second].pre){
			dict[p].pre.push_back(j);
			t++;
			if(t>=5) break;
		}
		if(t>=5) break;
	}	
}
void bckupdate(int p)
{
	
	auto it = dict[p].mp.end();
	it--;
	int pos = 0;

	for (;;it--) 
	{
		if(!dict[it->second].tag) pushdown(it->second); 
		for(int i=dict[it->second].bck.size()-1;i>=0;i--)
		{
			dict[p].bck.push_back(dict[it->second].bck[i]);
			pos++; 
			if(pos>=5) {
				reverse(dict[p].bck.begin(),dict[p].bck.end());break;
			}
		}
		if (pos >= 5)break;

		if(it==dict[p].mp.begin()) break;
	} 
	
}
void pushdown(int p)
{
	dict[p].pre.clear();
	dict[p].bck.clear();
	preupdate(p);
	if(dict[p].sz>10) bckupdate(p);
	else dict[p].bck=dict[p].pre;
	dict[p].tag=1;
}

void tree()
{
	if(!dict[now].tag) pushdown(now);
	int m = dict[now].sz;
	if(m==1) cout<<"EMPTY"<<endl;
	else if(m>1 && m<=10){
		for(int i=0;i<dict[now].pre.size();i++)
			cout<<dict[now].pre[i]<<endl;
	}
	else
	{
		for(int i=0;i<5;i++) cout<<dict[now].pre[i]<<endl;
		cout<<"..."<<endl;
		for(int i=5;i>=1;i--) cout<<dict[now].bck[dict[now].bck.size()-i]<<endl;
	}	
}

void init()
{
	cnt=0;now=0;
	v.clear();
	dict[0].init("root",-1);
}
void solve() {

	for (int i = 1; i <= n; ++i) {
		string s;
		cin >> s;
		cmd.init(s);
		int x = cmd.sign;
		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);
	cin>>T; 
	while(T--)
	{
		cin>>n;
		init();
		solve();
		cout<<endl;
	}
	return 0;
}

B - 东东学打牌

题意

最近,东东沉迷于打牌。所以他找到 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。请你告诉东东,全场人的排名
输入
输入包含多组数据。每组输入开头一个整数 n (1 <= n <= 1e5),表明全场共多少人。
随后是 n 行,每行一个字符串 s1 和 s2 (1 <= |s1|,|s2| <= 10), s1 是对应人的名字,s2 是他手里的牌情况。
输出
对于每组测试数据,输出 n 行,即这次全场人的排名。

思路
首先要将读入的牌的字符串进行处理,将字符串转换为5张牌的int值。依次判断字符串的每一位,2-9就是数字2-9,1就是数字10且字符串下一位要略过,字母AJQK就是1,11,12,13。
用struct player:string name,int pai[5]来存储玩家信息。将牌的字符串转换为int pai[5]后要进行升序排序,便于之后求手牌大小。
int value(int p[5],int a[3])用于求p[5]手牌大小,函数值返回手牌的大小1~8,a[3]返回值相同时比较要用的信息。根据题目所给信息依次写出8种手牌情况。(龙顺不是9 10 11 12 13而是1 10 11 12 13)
然后写player p1<p2的比较函数cmp。首先比较两者的手牌大小value1和value2,若值相同比较a[3]里的数据;若a也相同,则比较名字。注意名字字典序大的排在后面,即手牌值更小。
最后用sort函数进行升序排序,然后从后往前输出就行。

代码:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
const int maxn=1e5+5;
using namespace std;
struct player
{//结构体 存储每个人的信息
	string name;   //姓名
	int pok[5];    //牌
	int a,b,c,d;     //4个判断条件
	bool operator < (const player &x) const
	{//按条件级数判断
		if(a != x.a )   return a>x.a;
		if(b != x.b )	return b>x.b;
		if(c != x.c )   return c>x.c;
		if(d != x.d )	return d>x.d;
		return name<x.name;
	}	
} P[maxn];    
string poker;
int cnt;   

bool check8(int x)
{
     if(P[x].pok[0]==1&&P[x].pok[1]==10&&P[x].pok[2]==11&&P[x].pok[3]==12&&P[x].pok[4]==13) {P[x].a=8; return true;}
     return false;
}
bool check7(int x)
{

	if(P[x].pok[0]+1==P[x].pok[1]&&P[x].pok[1]+1==P[x].pok[2]&&P[x].pok[2]+1==P[x].pok[3]&&P[x].pok[3]+1==P[x].pok[4])
	{
		P[x].a=7;
		P[x].b=P[x].pok[4];
		return true;
	}
	else return false;

}

bool check6(int x)
{
    if(P[x].pok[0]==P[x].pok[1]&&P[x].pok[1]==P[x].pok[2]&&P[x].pok[2]==P[x].pok[3])
	{
		P[x].a=6;
		P[x].b=P[x].pok[0];
		P[x].c=P[x].pok[4];
		return true;
	}
	else if(P[x].pok[1]==P[x].pok[2]&&P[x].pok[2]==P[x].pok[3]&&P[x].pok[3]==P[x].pok[4])
	{
		P[x].a=6;
		P[x].b=P[x].pok[1];
		P[x].c=P[x].pok[0];
		return true;
	}
    else return false;
}
	
bool check5(int x)
{
    if(P[x].pok[0]==P[x].pok[1]&&P[x].pok[1]==P[x].pok[2]&&P[x].pok[3]==P[x].pok[4]){
        P[x].a=5;
		P[x].b=P[x].pok[0];
		P[x].c=P[x].pok[3]; return true;
    }
    else if(P[x].pok[0]==P[x].pok[1]&&P[x].pok[2]==P[x].pok[3]&&P[x].pok[3]==P[x].pok[4]){
        P[x].a=5;
		P[x].b=P[x].pok[2];
		P[x].c=P[x].pok[0]; return true;
    }
    return false;
}	

bool check4(int x)
{
    if(P[x].pok[0]==P[x].pok[1]&&P[x].pok[1]==P[x].pok[2]){
        P[x].a=4;
		P[x].b=P[x].pok[0];
		P[x].c=P[x].pok[3]+P[x].pok[4]; return true;
    }
    else if(P[x].pok[1]==P[x].pok[2]&&P[x].pok[2]==P[x].pok[3]){
        P[x].a=4;
		P[x].b=P[x].pok[1];
		P[x].c=P[x].pok[0]+P[x].pok[4]; return true;
    }
    else if(P[x].pok[2]==P[x].pok[3]&&P[x].pok[3]==P[x].pok[4]){
        P[x].a=4;
		P[x].b=P[x].pok[2];
		P[x].c=P[x].pok[0]+P[x].pok[1]; return true;
    }
    else return false;
}

bool check3(int x)
{
    if(P[x].pok[0]==P[x].pok[1]&&P[x].pok[4]==P[x].pok[3]){
        P[x].a=3;
		P[x].b=P[x].pok[3];
		P[x].c=P[x].pok[0];
		P[x].d=P[x].pok[2];return true;
    }
    else if(P[x].pok[2]==P[x].pok[1]&&P[x].pok[4]==P[x].pok[3]){
        P[x].a=3;
		P[x].b=P[x].pok[3];
		P[x].c=P[x].pok[1];
		P[x].d=P[x].pok[0]; return true;
    }
    else if(P[x].pok[0]==P[x].pok[1]&&P[x].pok[2]==P[x].pok[3]){
        P[x].a=3;
		P[x].b=P[x].pok[2];
		P[x].c=P[x].pok[0];
		P[x].d=P[x].pok[4]; return true;
    }
    else return false;
}
	
bool check2(int x)
{
    if(P[x].pok[0]==P[x].pok[1])
	{//属于2
		P[x].a=2;
		P[x].b=P[x].pok[0];
		P[x].c=P[x].pok[2]+P[x].pok[3]+P[x].pok[4];
		 return true;
	}
	else if(P[x].pok[1]==P[x].pok[2])
	{//属于2
		P[x].a=2;
		P[x].b=P[x].pok[1];
		P[x].c=P[x].pok[0]+P[x].pok[3]+P[x].pok[4];
		 return true;
	}
	else if(P[x].pok[2]==P[x].pok[3])
	{//属于2
		P[x].a=2;
		P[x].b=P[x].pok[2];
		P[x].c=P[x].pok[0]+P[x].pok[1]+P[x].pok[4];
		 return true;
	}
	else if(P[x].pok[3]==P[x].pok[4])
	{//属于2
		P[x].a=2;
		P[x].b=P[x].pok[3];
		P[x].c=P[x].pok[0]+P[x].pok[1]+P[x].pok[2];
		 return true;
	}
    else return false;
}


inline void judge(int x)//判断属于哪一种类型,并且赋值三个关键字
{
    if(check8(x)) return;
    else if(check7(x)) return;
    else if(check6(x)) return;
    else if(check5(x)) return;
    else if(check4(x)) return;
    else if(check3(x)) return;
    else if(check2(x)) return;
    else { 	P[x].a=1;P[x].b=P[x].pok[0]+P[x].pok[1]+P[x].pok[2]+P[x].pok[3]+P[x].pok[4]; return;}
}


int main()
{
	int n;
	while(scanf("%d",&n)==1)
	{
		for(int i=1; i<=n; i++)
		{
			cnt=0;
			cin>>P[i].name>>poker;     //读入姓名和牌
			for(int j=0; j<poker.length(); j++)
			{  //遍历牌  输入
			    if(poker[j]=='1')
				{//1为10  j++
					P[i].pok[cnt++]=10;
					j++;
				}
				else if(poker[j]=='A')
				{//A对应1
					P[i].pok[cnt++]=1;
				}
				else if(poker[j]>='2'&&poker[j]<='9')
				{//2-9 自身
					P[i].pok[cnt++]=poker[j]-'0';
				} 
				else if(poker[j]=='J')
				{//j==11
					P[i].pok[cnt++]=11;
				}
				else if(poker[j]=='Q')
				{//Q==12
					P[i].pok[cnt++]=12;
				}
				else if(poker[j]=='K')
				{//K==13
					P[i].pok[cnt++]=13;
				}
			    	
			}
			sort(P[i].pok,P[i].pok+5);   //将牌排序
			judge(i);   //获得判断各级条件
		}
		sort(P+1,P+1+n);  //排序
		for(int i=1;i<=n;i++)
		{ //输出姓名
			cout<<P[i].name<<endl;
		}
		for (int i=0; i<=n; i++)
            P[i].a=P[i].b=P[i].c=P[i].d=0;
	
	}
	return 0;
}

C 签到题,独立思考哈【模拟】

题意:
SDUQD 旁边的滨海公园有 x 条长凳。第 i 个长凳上坐着 a_i 个人。这时候又有 y 个人将来到公园,他们将选择坐在某些公园中的长凳上,那么当这 y 个人坐下后,记k = 所有椅子上的人数的最大值,那么k可能的最大值mx和最小值mn分别是多少。
输入:
第一行包含一个整数 x (1 <= x <= 100) 表示公园中长椅的数目;
第二行包含一个整数 y (1 <= y <= 1000) 表示有 y 个人来到公园;
接下来 x 个整数 a_i (1<=a_i<=100),表示初始时公园长椅上坐着的人数。
输出:mn和mx。

思路:
这个题目比较简单。要想求椅子上人数最大值的最大值就是让新来的所有人都坐到之前人数最多的长凳上。要想椅子上人数最大值的最小值需要将新来的所有人尽量坐到人数少的长凳上。

代码:

#include<iostream>
#include<algorithm>
using namespace std;
int x,y,a[110],mn,mx;
int main()
{
	scanf("%d %d",&x,&y);
	for(int i=1;i<=x;i++)
	cin>>a[i];
	sort(a+1,a+x+1);
	int t=0;
	for(int i=1;i<x;i++)
	t+=(a[x]-a[i]);
	if(t>=y) 	mn=a[x];
	else
	{	
		if((y-t)%x==0) mn=a[x]+((y-t)/x);
		else mn=a[x]+((y-t)/x)+1;
	}
	mx=a[x]+y,
	printf("%d %d\n",mn,mx);
return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值