SDU程序设计思维与实践作业Week9

A咕咕东的目录管理器

题目

题目
题目题目
input&&output

inputoutput附
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

#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

题解

1本题代码采用面向对象的方式编写
2.由于基本嫖自课堂助教,,因此不做分析
3.本题用到的思想比较惊艳的地方我认为是,模拟缓存的使用,极大的加快了目录索引效率

C++代码

#include <stdio.h>
#include <string>
#include <string.h>
#include <vector> 
#include <map>
#include <iterator>
using namespace std;

int T;
char tmps[20];

struct Directory{
	string name;					 //当前目录名称 
	map<string, Directory*> children;//找子 
	vector<string>* tenDescendants;//类似缓存 
	bool updated;//是否需要更新 
	Directory* parent;				 //以备cd..返回上级目录
	int subtreeSize;//子树大小 
	Directory(string newname, Directory* newparent){//构造 
		this->name=newname;
		this->parent=newparent;
		this->subtreeSize=1;
		this->updated=false;
		children.clear();
		tenDescendants=new vector<string>;
	} 
	public:	
		Directory *getChild(const string& newname){
			auto it=children.find(newname);
			if(it==children.end())
				return nullptr;
			return it->second;
		}
		Directory* mkdir(const string& newname){
			auto it=children.find(newname);
			if(it!=children.end())
				return nullptr;
			Directory* ch = new Directory(newname,this);
			children[newname]=ch;
			maintain(+1);
			return ch;
		}
		
		Directory* rm(const string& newname){
			auto it=children.find(newname);
			if(it==children.end())
				return nullptr;
			maintain(-1*(it->second->subtreeSize));
			children.erase(it);
			return it->second;
		}
		
		Directory* cd(const string& newname){
			if(".."==newname)
				return this->parent;
			return getChild(newname);
		}
		bool addChild(Directory* ch){
			auto it=children.find(ch->name);
			if(it!=children.end())
				return false;
			children[ch->name] = ch;
			maintain(ch->subtreeSize);
			return true;		
		}
		void maintain(int delta){
			updated=true;
			subtreeSize+=delta;
			if(parent!=nullptr)
				parent->maintain(delta);
		}
		void sz(){
			printf("%d\n",this->subtreeSize);
		}
		void ls(){
			int sz=children.size();
			if(sz==0) printf("EMPTY\n");
			else if(sz<=10){
				for(auto& entry:children)
					printf("%s\n",entry.first.c_str());
			}
			else{
				auto it=children.begin();
				for(int i=0;i<5;i++,it++)
					printf("%s\n",it->first.c_str());
				printf("...\n");
				it=children.end();
				for(int i=0;i<5;i++) it--;
				for(int i=0;i<5;i++,it++)
					printf("%s\n",it->first.c_str());
			}
		}
		void tree(){
			if(subtreeSize==1) printf("EMPTY\n");
			else if(subtreeSize<=10){
				if(this->updated){
					tenDescendants->clear();
					treeAll(tenDescendants);
					this->updated=false;
				}
				for(int i=0;i<subtreeSize;i++)
					printf("%s\n",tenDescendants->at(i).c_str());
			}else{
				if(this->updated){
					tenDescendants->clear();
					treeFirstSome(5,tenDescendants);
					treeLastSome(5,tenDescendants);
					this->updated=false;
				}
				for(int i=0;i<5;i++)
					printf("%s\n",tenDescendants->at(i).c_str());
				printf("...\n");
				for(int i=9;i>=5;i--)
					printf("%s\n",tenDescendants->at(i).c_str());
			}
		}
	private:
		void treeAll(vector<string>* bar){
			bar->push_back(name);
			for(auto &entry : children)
				entry.second->treeAll(bar);
		}
		void treeFirstSome(int num, vector<string>* bar){
			bar->push_back(name);
			if(--num==0) return;
			int n=children.size();
			auto it=children.begin();
			while(n--){
				int sts=it->second->subtreeSize;
				if(sts>=num){
					it->second->treeFirstSome(num,bar);
					return;
				}else{
					it->second->treeFirstSome(sts,bar);
					num-=sts;
				}
				it++;
			}
		}
		void treeLastSome(int num,vector<string>* bar){
			int n=children.size();
			auto it=children.end();
			while(n--)
			{
				it--;
				int sts=it->second->subtreeSize;
				if(sts>=num)
				{
					it->second->treeLastSome(num,bar);
					return;
				}else{
					it->second->treeLastSome(sts,bar);
					num-=sts;
				}
			}
			bar->push_back(name);
		}
};


struct Command{
	const string CMDNAMES[7]={"MKDIR","RM","CD","SZ","LS","TREE","UNDO"};
	int type;
	string arg;
	Directory* tmpDir;//刚刚操作的节点 
	Command(const string& s){
		tmpDir=nullptr;
		for (int i=0;i<7;i++) 
			if(CMDNAMES[i]==s){
				type=i;
				if(i<3) scanf("%s",tmps),arg=tmps;
				return;
			}
	}
};

void solve(){
	int n;
	scanf("%d",&n);
	Directory* now=new Directory("root",nullptr);
	vector<Command*> cmdList; 
	cmdList.clear();
	while(n--){
		scanf("%s",tmps);
		Command* cmd=new Command(tmps);
		switch(cmd->type){
			case 0:case 1:{//MKDIR、RM
				cmd->tmpDir=cmd->type==0? now->mkdir(cmd->arg) : now->rm(cmd->arg);
				if(cmd->tmpDir==nullptr) printf("ERR\n");
				else {
					printf("OK\n");
					cmdList.push_back(cmd);
				} 
				break;
			}
			case 2:{//CD
				Directory* ch=now->cd(cmd->arg);
				if(ch==nullptr) printf("ERR\n");
				else{
					printf("OK\n");
					cmd->tmpDir=now;
					now=ch;
					cmdList.push_back(cmd);
				}
				break;
			}
			case 3://SZ
				now->sz();
				break; 
			case 4://LS
				now->ls();
				break;
			case 5://TREE
				now->tree();
				break;
			case 6://UNDO 
			{
				bool success=false;
				while(!success && !cmdList.empty()){
					cmd=cmdList.back();
					cmdList.pop_back();
					switch(cmd->type){
						case 0:
							success=now->rm(cmd->arg)!= nullptr;
							break;
						case 1:
							success=now->addChild(cmd->tmpDir);
							break;
						case 2:
							now=cmd->tmpDir;
							success=true;
							break;
					}
				}
				printf(success ? "OK\n" : "ERR\n");
			}
		}
	}
}


int main(){
	scanf("%d",&T);
	for(int i=0;i<T;i++){
		solve();
		if(i!=(T-1)) printf("\n");
	}
	return 0;
}

B东东学打牌

题目

题目题目
input&&output
inputoutput
Sample

#input:
3
DongDong AAA109
ZJM 678910
Hrz 678910
#output:
Hrz
ZJM
DongDong

题解

1.本题实际上曾经做过类似的,我们只需要对牌型做一个排名就可以乐
2.八类牌,相同牌型之间按照牌型内部的顺序排列,牌相同按照姓名牌,我们只需要
写出一个排序函数就好了
首先我们只考虑牌型,八类牌分别为 1~8
此处我们利用(五张牌排序后的)一个差值数组,并且只关注其中差值为0 1的位置及个数
并且由于有龙顺,因此将牌扩展一位 默认15 含A则为14
大牌就是1,也就是不属于后七种
对子:0的个数为1 
三张:0的个数为2,与两对区别在非零的位置(或者我们可以注意到他的0是连续的位置)
两对:0的个数为2
三带二:0的个数3
炸弹:0的个数3,区别于三代二是 相同牌占位的跨度 XXXXA | AXXXX
顺子:1的个数为4
龙顺:1的个数为4,但第一个位置非零
注意:类似这种的数据  A123K  (也是四个1  顺子需要特判一下

然后我们看相同牌型:
我们发现 最多牌型相同时最多需要判断 三次(两对时 )
因此我们通过一个长度为4的数组记录整个牌的特征量
(牌型,第一特征,第二特征,第三特征)
如 AA223 -> [3,2,1,3]
PS:注意一对时第二特征为剩余牌的和

C++代码

#include<iostream>
#include<string>
#include<vector>
#include<algorithm>

using namespace std; 
struct p{
	string name;
	int poke[6];//出现A记录一个14
	int sum(){
		return poke[0]+poke[1]+poke[2]+poke[3]+poke[4];
	}
};
vector<p> v(0); 

int n;
char a[] = {'A','2','3','4','5','6','7','8','9','Z','J','Q','K'};
int c2n(char now){
	for(int i=0;i<sizeof a;i++)
		if(a[i]==now) return i+1;
}
int mark[16];

void typ(p x,int* re){
	for(int i=0;i<5;i++) re[i] = 0;//返回牌型 以及具体信息  0表示牌型 1对应牌型的第一标识 2 第二标识...  ————关于对子和三张 第二标识是剩余和!!! 2
	re[0] = 1;//默认是大牌 
	int diff[5],stat[2];//diff 差(特征)数组  stat 状态数组 只记录 差数组的 0 1 
	for(int i=0;i<5;i++) diff[i] = 0;
	stat[0] = 0,stat[1] = 0;
	for(int i=0;i<5;i++){
		diff[i] = x.poke[i+1]-x.poke[i];
		if(diff[i] == 0||diff[i] == 1) stat[diff[i]]++;
	}
	if(stat[0] == 1){//一对
		re[0] = 2;
		for(int i=4;i>=0;i--)
			if(re[1] == 0 && diff[i-1] == 0) re[1] = x.poke[i--];//升序排列后面的更大 
			else re[2] += x.poke[i]; 
	}
	if(stat[0] == 2){//三张 或 两对 
		if((diff[3]!=0&&(diff[0]!=0||diff[2]!=0)) || (diff[0] != 0 && diff[1] != 0)){//三张
			re[0] = 4,re[1] = x.poke[2],re[2] = x.sum()-3*re[1]; 
		}else{//两对
			re[0] = 3,re[1] = x.poke[3],re[2] = x.poke[1];
			if(diff[3] != 0) re[3] = x.poke[4];
			else if(diff[0] != 0) re[3] = x.poke[0];
			else re[3] = x.poke[2];
		}
	}
	if(stat[0] >= 3){//三代二 或 炸弹 
		if(x.poke[0] == x.poke[3] || x.poke[1] == x.poke[4]){//炸弹 
			re[0] = 6,re[1] = x.poke[2],re[2] = x.sum() - 4*re[1];
		}else{//0 1 2 3 4  五个位置 2一定是三张  然后根据1 2是否一样判断  
			re[0] = 5,re[1] = x.poke[2],re[2] = (x.sum() - 3*re[1])/2;
		}
	}
	if(stat[1] == 4){
		if(diff[0] != 1) re[0] = 8;
		else{//注意类似这种的数据  A123K  (也是四个1 
			if(x.poke[5] ==15 || (diff[0] == 1&&diff[1] == 1&&diff[2] == 1&&diff[3] == 1))
				re[0] = 7,re[1] = x.poke[4];
		}
	}
}

bool s(p p1,p p2){//< 是小的在前  >是大的在前 
	int rep1[5],rep2[5];
	typ(p1,rep1);
	typ(p2,rep2);
	for(int i=0;i<5;i++){
		if(rep1[i] != rep2[i])
			return rep1[i]>rep2[i];
	}
	if(rep1[0] == 1 && p1.sum() != p2.sum()) return p1.sum()>p2.sum();
	return p1.name<p2.name;
}
 
int main(){
	//freopen("in.txt","r",stdin);
	//freopen("out2.txt","w",stdout);
	while(cin>>n){
		v = vector<p>(0);
		v.clear(); 
		string now,name;
		while(n--){
			for(int i=0;i<15;i++) mark[i] = 0;//1-14计数 
			cin>>name>>now;
			int nowpoke[6];
			for(int i=0;i<6;i++) nowpoke[i] = 0;
			nowpoke[5] = 15;
			for(int i=0;i<now.length();i++){
				if(now[i]=='1') mark[10]++,i++;
				else mark[c2n(now[i])]++;
				if(now[i] == 'A' && mark[14] == 0){
					mark[14]++;
					nowpoke[5]=14;
				}
			}
			int pos = 0;
			for(int i=1;i<14;i++)
				for(int j=0;j<mark[i];j++)
					nowpoke[pos++] = i;
					
			sort(nowpoke,nowpoke+6);
			p ins;
			ins.name = name;
			for(int i=0;i<6;i++)
				ins.poke[i] = nowpoke[i];
			v.push_back(ins);
		}
		sort(v.begin(),v.end(),s);
		for(int i=0;i<v.size();i++)
			cout<<v[i].name<<endl;
	}
	return 0;
}

C签到题

题目

题目
input&&output
inputoutput
Sample

#input:
3
7
1
6
1
#output:
6 13

题解

1.本题思路很多我才用的偏数学
2.首先我们看最大的最大(mx):
	这个比较简单,我们只需要把新来的全安排到原有的最多的椅子上就可
	然后肯最小的最大(mn):
	我们会偏向于让最大值更小,因此先将人分配到小于当前最大的椅子上,然后每
	个椅子分配一个直到分配结束
	因此我们先将所有椅子的人数补到目前的最大个数,若无剩余或补不全则mn为当
	前的最大个数,若补全我们只需要每个椅子分配一个人也就是除运算,如果刚刚
	分配合理(mod运算为0)则为最大个数加除运算结果,否则再加一

C++代码

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
vector<int> v(0);
int x,y,c,mx,mn;


int main(){
	cin>>x>>y;
	for(int i=0;i<x;i++){
		cin>>c;
		v.push_back(c);
	}
	sort(v.begin(),v.end());
	mx = v[x-1] + y;
	long long sum=y;
	for(int i=0;i<v.size();i++)
		sum+=v[i] - v[x-1];
	//sum-=x-1;
	if(sum<=0) mn = v[x-1];
	else{
		int add;
		if(sum%x == 0) add=0;
		else add = 1;
		mn = v[x-1] + sum/x + add;
	}

	cout<<mn<<" "<<mx;
	return 0;
} 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值