zoukankan      html  css  js  c++  java
  • Week9 作业 A

    题目描述:

    传送门

    思路:

    真的是不知道该说什么,因为我一直WA,简直要Crazy了....自己造数据对拍了很长时间,也没找到问题所在,后来(被迫)借鉴了标准代码,如果能找到测试点,则我的程序还能有救

    但是还是要说一下主要的点:

    • 查多改少,可以使用懒更新,或者说记忆化,防止重复计算;查多改少可以根据仔细分析数据范围得出
    • 输出树的前五个节点比较容易,但是输出树的后五个节点就不那么容易,仍然可以使用递归,递归时要记录现在还需要输出多少个节点,不要使用引用而是使用传值
    • 但是我是真的不知道,下述代码为什么WA...,毕竟这是道模拟,没有那么重要,等有机会重写一下,再研究

    代码:

    WA代码:

    //可能连续多次UNDO,所以所有的操作命令都要存储
    //1s , 1e8 
    //6s , 6e8
    //很多次查询,要善于利用缓存的思想,因为计算已经知道的答案代价高
    //特别是对于,查多改少(分析输入数据)的情况,记忆画能省很多时间
    //考虑用这节课的动态分配内存去修改树和森林 
    //记录size? 遍历需要O(n),向上层更新需要O(h),可以都试试? 
    #include <cstdio>
    #include <iostream>
    #include <map>
    #include <string>	 
    #include <stack>
    #include <vector>
    #include <algorithm>
    using namespace std;
    struct subTree
    {
    	string name;
    	map<string,subTree*> children;
    	subTree *parent; 
    	int treeSize;
    	bool dirty; //脏位 
    	vector<string> tenChildren;
    	subTree(const string &ts,subTree *p) { dirty=1; treeSize=1; name=ts; parent=p; children.clear();tenChildren.clear();  }
    };
    class directory 	//目录是一层一层进入的,所以必须指明找到每个节点的路径,和DSA2略微不同? 
    {
    	protected:
    		subTree *root,*now;
    		stack< pair<int,string> > op;  //执行过的操作,如果是删除目录,很可能把子目录也删除了,这时候删除的目录,只删除关系,不删除内存
    		stack<subTree*> trashBin; 
    		void updateSize(int ); 	
    		void preOutput(subTree *);
    		void preOutFirst(int ,subTree *);
    		void postOutLast(int ,subTree *); 	
    	public:
    		directory()
    		{ 
    			root=new subTree("root",nullptr);
    			now=root;
    		}
    		void makeDir(string &);
    		void removeDir(string &);
    		void cd(const string &);
    		int sizeOfNowDir() { return now->treeSize; }
    		void listNowDir();
    		void printNowDir();
    		void undo();
    };
    void directory::updateSize(int delta)  //delta==Δ 没问题 
    {
    	now->treeSize+=delta;
    	now->dirty=1; 
    	auto p=now->parent;
    	while(p!=nullptr)
    	{
    		p->dirty=1;
    		p->treeSize+=delta;
    		p=p->parent;
    	}
    }
    void directory::preOutput(subTree *p)
    {
    	cout<<p->name<<endl;
    	now->tenChildren.push_back(p->name);
    	for(auto &child:p->children)
    		preOutput(child.second);
    }
    void directory::preOutFirst(int num,subTree *p) 
    {
    	now->tenChildren.push_back(p->name);
    	if(--num==0) return;
    	
    	int n=p->children.size();
    	auto it=p->children.begin();
    	while(n--)
    	{
    		int sts=it->second->treeSize;
    		if(sts>=num)
    		{
    			preOutFirst(num,it->second);
    			return;
    		}
    		else
    		{
    			preOutFirst(sts,it->second);
    			num-=sts;
    		}
    		it++;
    	}		
    }
    void directory::postOutLast(int num,subTree *p) 
    {
    	int n=p->children.size();
    	auto it=p->children.end();
    	while(n--)
    	{
    		it--;
    		int sts=it->second->treeSize;
    		if(sts>=num)
    		{
    			postOutLast(num,it->second);
    			return;
    		}
    		else
    		{
    			postOutLast(sts,it->second);
    			num-=sts;
    		}
    	}
    	now->tenChildren.push_back(p->name);	
    }
    void directory::makeDir(string &ts)  //没问题 
    {
    	if(now->children.find(ts)!=now->children.end())
    	{
    		//已经有这个目录 
    		cout<<"ERR"<<endl;
    		return;
    	}
    	//新建一个目录 
    	subTree *newNode=new subTree(ts,now);
    	now->children[ts]=newNode;
    	updateSize(1);	//更新这层及上层节点数量 
    	cout<<"OK"<<endl;
    	op.push(make_pair(1,ts));	//存储成功的操作 
    }
    void directory::removeDir(string &ts)	//没问题 
    {
    	if(now->children.find(ts)==now->children.end())
    	{
    		//如果要删除的目录不存在 
    		cout<<"ERR"<<endl;
    		return;
    	}
    	//删除目录,把目录的内存放进垃圾桶trashBin 
    	trashBin.push(now->children[ts]);
    	updateSize(-now->children[ts]->treeSize);  //删除的是整个文件夹,包括子目录 
    	now->children.erase(ts);
    	cout<<"OK"<<endl;
    	op.push(make_pair(2,ts)); 
    }
    void directory::cd(const string &ts)	//没问题 
    {
    	if(ts=="..")
    	{
    		if(now==root) cout<<"ERR"<<endl;
    		else 
    		{
    			//回到上层目录,则把当前的目录名存起来 
    			op.push(make_pair(3,now->name)); 
    			now=now->parent;
    			cout<<"OK"<<endl;
    		}
    		return;
    	}
    	
    	if(now->children.find(ts)==now->children.end())
    	{
    		cout<<"ERR"<<endl;
    		return;
    	}
    	op.push(make_pair(4,now->name)); //其实进入内层目录可以用父亲指针跳出来 
    	now=now->children[ts];
    	cout<<"OK"<<endl;
    }
    void directory::listNowDir()	//没问题 
    {
    	if(now->children.empty())
    	{
    		cout<<"EMPTY"<<endl;
    		return;
    	}
    	if(now->children.size()<=10)
    	{
    		for(auto x:now->children)
    			cout<<x.first<<endl; 
    		return;
    	}
    	auto itb=now->children.begin(),ite=now->children.end();
    	for(int i=1;i<=5;i++)
    	{
    		cout<<itb->first<<endl;
    		++itb;
    		ite--;
    	}
    	cout<<"..."<<endl;
    	for(int i=1;i<=5;i++)
    	{
    		cout<<ite->first<<endl;
    		++ite;
    	}
    }
    void directory::printNowDir()	//没问题 
    {
    	if(now->treeSize==1)
    	{
    		cout<<"EMPTY"<<endl;
    		return;
    	}
    	if(now->dirty==0)
    	{
    		for(auto x:now->tenChildren)
    			cout<<x<<endl;
    		return; 
    	}
    	now->tenChildren.clear();
    	now->dirty=0;
    	if(now->treeSize<=10)
    	{
    		preOutput(now);
    		return;
    	}
    	//前序5个,后序五个
    	preOutFirst(5,now);
    	now->tenChildren.push_back("...");
    	postOutLast(5,now);
    	reverse(now->tenChildren.begin()+6,now->tenChildren.end());
    	for(auto x:now->tenChildren)
    		cout<<x<<endl;
    }
    void directory::undo()
    {
    	if(op.empty())
    	{
    		cout<<"ERR"<<endl;
    		return;
    	}
    	auto t=op.top();
    	op.pop();
    	switch(t.first)
    	{
    		case 1:removeDir(t.second);break;
    		case 2:	//把垃圾桶的东西整体回收
    			now->children[t.second]=trashBin.top();
    			cout<<"OK"<<endl; 
    			updateSize(trashBin.top()->treeSize);
    			trashBin.pop();
    			break;
    		case 3:cd(t.second);break;   //cd..的负操作
    		case 4:cd("..");break; 
    	}
    }
    
    int main()
    {
    //	freopen("a.in","r",stdin);
    //	freopen("a.out","w",stdout);
    	int T; cin>>T;
    	int first=1; 
    	while(T--)
    	{
    		if(!first) cout<<endl;
    		directory C; 
    		int Q; cin>>Q;
    		while(Q--)
    		{
    			string op,obj;
    			cin>>op;
    			if(op=="MKDIR") cin>>obj,C.makeDir(obj); 
    			else if(op=="RM") cin>>obj,C.removeDir(obj);
    			else if(op=="CD")
    			{
    				cin>>obj;
    				C.cd(obj);
    			}
    			else if(op=="SZ")
    				cout<<C.sizeOfNowDir()<<endl;
    			else if(op=="LS") C.listNowDir();
    			else if(op=="TREE") C.printNowDir();
    			else if(op=="UNDO") C.undo();
    		}
    		first=0;
    	}
    	return 0;
    } 

    AC代码:

    #include <cstdio>
    #include <iostream>
    #include <vector>
    #include <map>
    using namespace std;
    char tmps[20];
    struct Directory
    {
    	string name;//当前目录的名字
    	map<string, Directory*>children;
    	Directory* parent;//以备CD.. 返回上级目录
    	int subtreeSize;//以备sz要输出子树大小
    	vector<string>* tenDescendants;//保存当前节点的十个后代
    	Directory(string name, Directory* parent) 
    	{
    		this->name = name;
    		this->parent = parent;
    		this->subtreeSize = 1;
    		this->tenDescendants=new vector<string>;		
    	}	
    	bool updated;//记录当前节点的子孙有无变动,无变动则十个后代无需更新
    public:
    	void maintain(int delta) //向上维护子树大小
    	{
    		updated = true;
    		subtreeSize += delta;
    		if (parent != nullptr)
    			parent->maintain(delta);	
    	}
    	void tree() 
    	{
    		if (subtreeSize == 1) printf("EMPTY
    ");
    		else if (subtreeSize <= 10) 
    		{			
    			if (this->updated) 
    			{				
    				tenDescendants->clear();				
    				treeAll(tenDescendants);
    				this->updated = false;
    			}
    			for (int i = 0; i < subtreeSize; i++)
    			{
    				printf("%s
    ", 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
    ", tenDescendants->at(i).c_str());
    			}	
    			printf("...
    ");
    			for (int i = 9; i >= 5; i--)
    			{
    				printf("%s
    ", tenDescendants->at(i).c_str());
    			}		
    		}
    	}	
    	Directory* getChild(string name) //取子目录并返回,不存在返回空指针
    	{
    		auto it = children.find(name);
    		if (it == children.end()) return nullptr;
    		return it->second;
    	}
    	Directory* mkdir(string name) //创建子目录并返回,创建失败返回空指针
    	{
    		if (children.find(name) != children.end()) return nullptr;		 
    		Directory* ch = new Directory(name, this);
    		children[name] = ch;
    		maintain(+1);
    		return ch;
    	}	
    	Directory* rm(string name) 	//删除子目录并返回,删除失败返回空指针
    	{
    		auto it = children.find(name);
    		if (it == children.end()) return nullptr;		
    		maintain(-1 * it->second->subtreeSize);		
    		children.erase(it);
    		return it->second;
    	}
    	Directory* cd(string name) 
    	{
    		if (".." == name) 
    		{
    			return this->parent;
    		}
    		return getChild(name);
    	}
    	bool addChild(Directory* ch)//加入子目录并判断成功与否 
    	{
    		if (children.find(ch->name) != children.end())
    		{
    			return false;
    		}
    		children[ch->name] = ch;
    		maintain(+ch->subtreeSize);
    		return true;
    	}
    	void sz() 
    	{
    		printf("%d
    ", this->subtreeSize);
    	}
    	void ls() 
    	{
    		int sz = children.size();		
    		if (sz == 0) printf("EMPTY
    ");
    		else if (sz <= 10)
    		{
    			for (auto& entry : children)
    			{
    				printf("%s
    ", entry.first.c_str());
    			}	
    		}	
    		else 
    		{
    			auto it = children.begin();
    			for (int i = 0; i < 5; i++, it++)
    			{
    				printf("%s
    ", it->first.c_str());
    			}	
    			printf("...
    ");
    			it = children.end();
    			for (int i = 0; i < 5; i++) it--;
    			for (int i = 0; i < 5; i++, it++)
    			{
    				printf("%s
    ", it->first.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
    {
    	int type;//命令的类型
    	string arg;//命令的参数
    	const string CMDNAMES[7] = { "MKDIR","RM","CD","SZ","LS","TREE","UNDO" };
    	Command(string s) 
    	{//构造函数
    		for(int i=0;i<7;i++)
    			if (CMDNAMES[i] == s) 
    			{
    				type = i;
    				if (i < 3) 	//MKDIR、RM、CD的参数后续读入
    				{
    					scanf("%s", tmps), arg = tmps;
    				}
    				return;
    			}
    	}
    	Directory* tmpDir;//记录刚刚操作涉及的目录节点
    };
    
    void solve()
    {
    	int n;
    	cin>>n;
    	//scanf("%d",&n); //每组数据有m行命令
    	Directory *now = new Directory("root", nullptr);
    	vector<Command*>cmdList;//新增加的数组存成功执行的命令以备undo
    	while (n--) 
    	{
    		scanf("%s", tmps);
    		Command* cmd = new Command(tmps);
    		switch (cmd->type)
    		{
    			case 0://MKDIR
    				{
    					cmd->tmpDir = now->mkdir(cmd->arg);
    					if (cmd->tmpDir == nullptr) printf("ERR
    ");
    					else 
    					{
    						printf("OK
    ");
    						cmdList.push_back(cmd);
    					}
    					break;
    				}
    			case 1://RM
    				{
    					cmd->tmpDir = now->rm(cmd->arg);
    					if (cmd->tmpDir == nullptr) printf("ERR
    ");
    					else 
    					{
    						printf("OK
    ");
    						cmdList.push_back(cmd);
    					}
    					break;
    				}
    			case 2://CD
    			{
    				Directory * ch = now->cd(cmd->arg);
    				if (ch == nullptr)printf("ERR
    ");
    				else 
    				{
    					printf("OK
    ");
    					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;//undo执行成功与否
    				while (!success && !cmdList.empty()) 
    				{
    					cmd = cmdList.back(); cmdList.pop_back();
    					switch (cmd->type)
    					{
    						case 0://UNDO MKDIR 
    							success = now->rm(cmd->arg) != nullptr; 
    							break;
    						case 1://UNDO RM
    							success = now->addChild(cmd->tmpDir); 
    							break;
    						case 2:	//UNDO CD
    							now = cmd->tmpDir; 
    							success = true; 
    							break;
    					}
    				}
    				printf(success ? "OK
    " : "ERR
    ");
    			}		
    		}
    	}
    	printf("
    ");
    }
    int main()
    {
    	int T; cin>>T;
    	while(T--)
    		solve();
    	return 0;
    }
    

      

  • 相关阅读:
    斐波那契数列
    MySQL
    GIT
    shell执行Python并传参
    摘选改善Python程序的91个建议2
    摘选改善Python程序的91个建议
    django执行原生sql
    admin
    分支&循环
    git
  • 原文地址:https://www.cnblogs.com/qingoba/p/13090326.html
Copyright © 2011-2022 走看看