CCF201809-3

CCF201809-3

我的程序

#include<iostream>
#include<string>
#include<vector>
#include<algorithm>
#include<cstring>
using namespace std;

typedef struct TreeNode {
	string label;
	string id;
	int LineNum;
	int DotNum;
	struct TreeNode* child;
	struct TreeNode* bother;
	struct TreeNode* father;
	TreeNode() {					//结构体初始化
		this->label = "";
		this->id = "";
		this->LineNum = 0;
		this->DotNum = -1;
		this->father = NULL;
		this->bother = NULL;
		this->child = NULL;
	}
}TreeNode, * TreeNodePointer;

class solution {
private:
	TreeNodePointer root;
	TreeNodePointer recent;

public:
	solution() {
		root = new TreeNode;
		recent = root;
	}
	void Insert(TreeNodePointer t) {			//由上一个插入节点向上回溯,避免匹配错误
		TreeNodePointer p = recent;
		if (t->DotNum > p->DotNum) {
			p->child = t;
		}
		else if (t->DotNum == p->DotNum) {
			p->bother = t;
		}
		else {
			while (p->DotNum != t->DotNum) {
				p = p->father;
			}
			while (p->bother) {   //实际上没有必要,因为在与t相同级数的节点中,该子树节点与t是最后两个
				p = p->bother;
			}
			p->bother = t;
		}

		t->father = p;
		recent = t;
	}
	static bool CompareLabel(TreeNodePointer t, string SelectItem) {
		return t->label == SelectItem;
	}
	static bool CompareId(TreeNodePointer t, string SelectItem) {
		return t->id == SelectItem;
	}
	void find(bool(*compare)(TreeNodePointer t, string SelectItem), string SelectItem, TreeNodePointer r, vector<int>& ans) {
		if (r == NULL)
			return;
		if (compare(r, SelectItem))
			ans.push_back(r->LineNum);
		find(compare, SelectItem, r->child, ans);
		find(compare, SelectItem, r->bother, ans);
	}
	vector<int> FindLabel(string SelectItem) {
		vector<int> ans;
		find(CompareLabel, SelectItem, root, ans);
		return ans;
	}
	vector<int> FindId(string SelectItem) {
		vector<int> ans;
		find(CompareId, SelectItem, root, ans);
		return ans;
	}
	void FindLast(vector<string>& SelectItems, TreeNodePointer r, vector<int>& ans, int size) {
		if (r == NULL)
			return;
		if (r->id == SelectItems[size - 1] || r->label == SelectItems[size - 1]) {
			int flag = size - 2;
			TreeNodePointer p = r;
			while (p->father) {
				p = p->father;
				if (p->id == SelectItems[flag] || p->label == SelectItems[flag]) {
					flag--;
				}
				if (flag < 0) {
					break;
				}
			}
			if (flag < 0)
				ans.push_back(r->LineNum);
		}
		FindLast(SelectItems, r->child, ans, size);
		FindLast(SelectItems, r->bother, ans, size);
	}
	vector<int> MultipleFind(vector<string>& SelectItems) {
		vector<int> ans;
		FindLast(SelectItems, root, ans, SelectItems.size());
		return ans;
	}
};


void func() {
	solution tree;
	int m, n;
	cin >> n >> m;
	char c = getchar();				//消除换行符
	for (int i = 1;i <= n;i++) {						//构建结构树
		string label, id, line;
		int DotNum = 0;

		getline(cin, line);
		int j = 0;
		while (line[j] == '.') {				//计算小数点
			j++;
			DotNum++;
		}
		if (DotNum > 0) {
			line.erase(0, DotNum);
		}

		int index = line.find("#");		//分离label和id
		if (index != string::npos) {
			id = line.substr(index);
			label = line.substr(0, index - 1);
		}
		else {
			id = "";
			label = line;
		}
		transform(label.begin(), label.end(), label.begin(), ::tolower);			//标签选择器对于大小写不敏感


		TreeNodePointer tmp = new TreeNode;
		tmp->DotNum = DotNum;
		tmp->id = id;
		tmp->label = label;
		tmp->LineNum = i;
		tree.Insert(tmp);
	}

	string* SelectItems = new string[m];			//选择器查询
	for (int i = 0;i < m;i++) {
		getline(cin, SelectItems[i]);
	}
	for (int i = 0;i < m;i++) {
		vector<int> ans;
		int index = SelectItems[i].find(" ");
		if (index != string::npos) {			//多重选择器
			vector<string> query;
			char* sp = strtok((char*)SelectItems[i].c_str(), " ");//将插叙用空格分割,按序存放在query向量中 
			while (sp)
			{
				string tmp(sp);
				if (tmp[0] != '#') {
					transform(tmp.begin(), tmp.end(), tmp.begin(), ::tolower);
				}
				query.push_back(tmp);
				sp = strtok(NULL, " ");
			}
			ans = tree.MultipleFind(query);
		}
		else {
			if (SelectItems[i][0] == '#') {				//id选择器
				ans = tree.FindId(SelectItems[i]);
			}
			else {										//标签选择器
				ans = tree.FindLabel(SelectItems[i]);
			}
		}

		sort(ans.begin(), ans.end());
		cout << ans.size() << " ";
		for (int j = 0;j < ans.size();j++) {
			cout << ans[j] << " ";
		}
		cout << endl;
	}
}

int main() {
	func();
	return 0;
}

别人的程序
引用自CCF CSP 真题题解


#include<iostream>
#include<string>
#include<cstring>
#include<vector>
 
using namespace std;
 
const int N=105;
 
struct Node{
	string lable,id;//标签和属性 
	int cnt;//缩进 
}a[N];
 
//将字符串化成小写 
void mystrlwr(string &s)
{
	for(int i=0;i<s.length();i++)
	  s[i]=tolower(s[i]);
}
 
//在数组a中[1,start]寻找缩进小于cnt,且标签或属性等于s的元素 
bool search(Node a[],int &start,int &cnt,string s)
{
	for(int i=start;i>=1;i--)//遍历 
	{
		if(a[i].cnt<cnt) 
		{
			//查询成功
			cnt=a[i].cnt,start=i;//保证a[i]是它的父亲,即第一个缩进小于它的元素 
			if(s==a[i].lable||s==a[i].id) return true;//成功 
		}
	}
	return false;//查询失败 
}
 
int main()
{
	int n,m;
	string s;
	cin>>n>>m;//读入n和m 
	getchar();//读取换行符 
	for(int i=1;i<=n;i++)
	{
		getline(cin,s);
		//pos1记录标签的起始位置,pos2记录id属性的起始位置,cnt记录缩进 
		int pos1=-1,pos2=-1,cnt=0; 
		for(int j=0;j<s.length();j++)
		  if(s[j]=='.')
		    cnt++;
		  else if(pos1==-1&&s[j]!='#')
		    pos1=j;
		  else if(s[j]=='#')
		    pos2=j;
		a[i].cnt=cnt;
		if(pos2==-1)//如果不存在id属性 
		{
			a[i].lable=s.substr(pos1);
			a[i].id="";//置为空 
		}
		else//存在id属性 
		{
			a[i].lable=s.substr(pos1,pos2-pos1-1);
			a[i].id=s.substr(pos2);
		}
		mystrlwr(a[i].lable);//由于标签属性大小写不敏感,因此统一换成小写 
	}
	for(int i=0;i<m;i++)//读入m个查询 
	{
		char tmp[100];
		vector<string>query;//存储查询 
		vector<int>ans;//存储结果 
		gets(tmp);//读入 
		char *sp=strtok(tmp," ");//将插叙用空格分割,按序存放在query向量中 
		while(sp)
		{
			query.push_back(sp);
			sp=strtok(NULL," ");
		}
		int len=query.size();
		for(int j=0;j<len;j++)//将标签统一化成小写 
		  if(query[j][0]!='#')  mystrlwr(query[j]);
		for(int j=1;j<=n;j++)//遍历n行元素 
		{
			if(query[len-1]==a[j].id||query[len-1]==a[j].lable)//最后一级选择器匹配了 
			{
				int start=j,cnt=a[j].cnt,k=len-2;//使用search函数匹配各级父选择器 
				for(;k>=0;k--)
				{
					if(!search(a,start,cnt,query[k])) break;
				}
				if(k<0)//成功
				  ans.push_back(j); 
			}
		}
		//输出结果 
		cout<<ans.size();
		for(int j=0;j<ans.size();j++)
		  cout<<" "<<ans[j];
		cout<<endl;
	}
	return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

最佳损友1020

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值