CCF-CSP【202303-3 LDAP】C++

CCF-CSP【202303-3 LDAP】C++

CCF真题网址

第一次提交结果超时 只有20分

题目思路

我的思路较为简单,即对于每个匹配表达式,遍历N个用户,验证是否匹配。
对于每个表达式有两种情况:

  1. 原子表达式
  2. 复杂表达式

对于原子表达式,我们利用编写的函数atomic_expression()进行求解。由于不确定属性及属性值的位数,所以直接find()断言操作符:或者~,之后将断言操作符左边的提取为属性,将断言操作符右边的提取为属性值。
对于复杂表达式,我们需要考虑&(1:2)(2:3)&(|(1:2)(3~4))(555:666)以及更复杂的嵌套更多的表达式。我们自然选择递归。
那么如何递归呢,由于表达式的语法是:<操作符>(表达式 1)(表达式 2),我们的任务就是找到表达式1的(),那么表达式2的()自然也就得到了。
如果表达式1中含有嵌套表达式,如何找到表达式1的)呢?
我的想法是找到第一个),使其前面的字符串(包含它)中的()的个数相等。
递归的终止条件就是字符串是原子表达式,及字符串第一个字符不是给定的操作符。
已知如何递归以及递归的终止条件,自然就可以完成代码的编写!
main函数主要是对输入及输出的处理。

基础知识补充

C++中s.find()和s.rfind()的用法
正向查找find()

  1. s.find(str)
    string中find()返回值是字母在母串中的第一次出现的下标位置。如果没有找到,那么会返回-1
  2. s.find(str, pos)
    find(str,pos)是用来寻找从pos开始**(包括pos处字符)**匹配str的位置。

C++代码

#include 
#include 
#include 
#include 
#include 
#include 
#include 

using namespace std;


bool atomic_expression(int dn, string s, map<int, map<int, int>> m_dn_at){
	//1:2
	//3~1
	if(s.find(':') != -1){
		int index = s.find(':');
		string s_a = s.substr(0, index);
		string s_b = s.substr(index+1);
		int i_a = stoi(s_a);
		int i_b = stoi(s_b);
		return m_dn_at[dn].count(i_a) > 0 and m_dn_at[dn][i_a] == i_b;
	}
	else if(s.find('~') != -1){
		int index = s.find('~');
		string s_a = s.substr(0, index);
		string s_b = s.substr(index+1);
		int i_a = stoi(s_a);
		int i_b = stoi(s_b);
		return m_dn_at[dn].count(i_a) > 0 and m_dn_at[dn][i_a] != i_b;
	}
}


bool resolve(int dn, string s, map<int, map<int, int>> m_dn_at){
	// &(|(1:2)(3~4))(555:666)
	if(s[0] == '&' or s[0] == '|'){
		int l_l = s.find('(');
		int l_r = s.find(')');
		while(count(s.begin()+l_l, s.begin()+l_r+1, '(') != count(s.begin()+l_l, s.begin()+l_r+1, ')')){
			l_r = s.find(')', l_r+1);
		}
		string s_l = s.substr(l_l+1, l_r-l_l - 1);
		
		int r_l = l_r+1;
		int r_r = s.rfind(')');
		string s_r = s.substr(r_l+1, r_r-r_l-1);
		if(s[0]=='&')
			return resolve(dn, s_l, m_dn_at) and resolve(dn, s_r, m_dn_at);
		else
			return resolve(dn, s_l, m_dn_at) or resolve(dn, s_r, m_dn_at);
	}
	else
		return atomic_expression(dn, s, m_dn_at);
}


int main(){
	// 输入处理
    int n,m;
    cin >> n;
	map<int, map<int, int>> m_dn_at;
	vector<int>v_dn;
    for(int i = 0; i < n; i++){
    	int dn;
		cin >> dn;
		v_dn.push_back(dn);
    	int num;
		cin >> num;
		map<int, int> m_at;
		for(int j = 0; j < num; j++){
			int a,b;
			cin >> a >> b;
			m_at[a] = b;
		}
		m_dn_at[dn] = m_at;
	}
	
    cin >> m;
	vector<string> v_s;
    for(int i = 0; i < m; i++){
		string s;
    	cin >> s;
    	v_s.push_back(s);
	}
	
	for(int i = 0; i < m; i++){
		string s = v_s[i];
		
		vector<int>r_dn;
		for(int j = 0; j < n; j++){
			if(resolve(v_dn[j], s, m_dn_at))
				r_dn.push_back(v_dn[j]);
		}
		sort(r_dn.begin(), r_dn.end());
		for(int k=0; k<r_dn.size(); k++)
			cout << r_dn[k] << " ";
		cout << endl;
	}
}

第二次提交结果超时 40分

题目思路

我的改进主要是参考了这篇文章,我对以上代码的修改仅限于atomic_expression以及resolve的返回类型。
对于每个原子表达式,获取符合表达式的LD集合,之后进行交并集操作。
对于代码的一些解释,atomic_expression函数中index = min(s.find(':'), s.find('~'));正常情况下s.find(':')s.find('~')必然有一个-1,另一个>0,我们想要获取>0index,应该选择max而不是min,但是-1在此函数中对应的是18446744073709551615,所以需要选择min

基础知识补充

map操作
map及set都是通过迭代器进行遍历,区别在于map读取元素的方式为it->firstit->second,而set读取元素的方式为*iter
map及set数据结构的遍历如下所示:

    map<int, map<int, int>>::iterator it = m_dn_at.begin() ;
	for(; it!= m_dn_at.end(); it++){
		if(m_dn_at[it->first].count(i_a) > 0 and m_dn_at[it->first][i_a] == i_b)
			s_a.insert(it->first);
		if(m_dn_at[it->first].count(i_a) > 0 and m_dn_at[it->first][i_a] != i_b)
			s_b.insert(it->first);
	}
	
	set<int>::iterator iter;
	for(iter = s_r.begin(); iter != s_r.end(); iter++){
		cout << *iter << " ";
	}

集合求取交并集
集合求取交并集:

    set_intersection(s_a.begin(), s_a.end(), s_b.begin(), s_b.end(), inserter(s_is, s_is.begin()));
	set_union(s_a.begin(), s_a.end(), s_b.begin(), s_b.end(), inserter(s_u, s_u.begin()));

C++代码

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

using namespace std;


set<int> atomic_expression(string s, map<int, map<int, int>> m_dn_at){
	//1:2
	//3~1
	int index = min(s.find(':'), s.find('~'));
	string a = s.substr(0, index);
	string b = s.substr(index+1);
	int i_a = stoi(a);
	int i_b = stoi(b);
	
	set<int> s_a, s_b, s_c;
	
//  https://blog.csdn.net/segegefe/article/details/124164513
    map<int, map<int, int>>::iterator it = m_dn_at.begin() ;

	for(; it!= m_dn_at.end(); it++){
		if(m_dn_at[it->first].count(i_a) > 0 and m_dn_at[it->first][i_a] == i_b)
			s_a.insert(it->first);
		if(m_dn_at[it->first].count(i_a) > 0 and m_dn_at[it->first][i_a] != i_b)
			s_b.insert(it->first);
	}
	
	if(s[index] == ':')
	    return s_a;
	else
		return s_b;
}


set<int> resolve(string s, map<int, map<int, int>> m_dn_at){
	// &(|(1:2)(3~4))(555:666)
	if(s[0] == '&' or s[0] == '|'){
		int l_l = s.find('(');
		int l_r = s.find(')');
		while(count(s.begin()+l_l, s.begin()+l_r+1, '(') != count(s.begin()+l_l, s.begin()+l_r+1, ')')){
			l_r = s.find(')', l_r+1);
		}
		string s_l = s.substr(l_l+1, l_r-l_l - 1);
		
		int r_l = l_r+1;
		int r_r = s.rfind(')');
		string s_r = s.substr(r_l+1, r_r-r_l-1);
		
		set<int> s_a, s_b, s_is, s_u;
		s_a = resolve(s_l, m_dn_at);
		s_b = resolve(s_r, m_dn_at);
	    set_intersection(s_a.begin(), s_a.end(), s_b.begin(), s_b.end(), inserter(s_is, s_is.begin()));
		set_union(s_a.begin(), s_a.end(), s_b.begin(), s_b.end(), inserter(s_u, s_u.begin()));
		if(s[0]=='&')
			return s_is;
		else
			return s_u;
	}
	else
		return atomic_expression(s, m_dn_at);
}


int main(){
    int n,m;
    cin >> n;
	map<int, map<int, int>> m_dn_at;
	vector<int>v_dn;
    for(int i = 0; i < n; i++){
    	int dn;
		cin >> dn;
		v_dn.push_back(dn);
    	int num;
		cin >> num;
		map<int, int> m_at;
		for(int j = 0; j < num; j++){
			int a,b;
			cin >> a >> b;
			m_at[a] = b;
		}
		m_dn_at[dn] = m_at;
	}
	
    cin >> m;
	vector<string> v_s;
    for(int i = 0; i < m; i++){
		string s;
    	cin >> s;
    	v_s.push_back(s);
	}
	for(int i = 0; i < m; i++){
		string s = v_s[i];
		set<int> s_r;
		s_r = resolve(s, m_dn_at);
		set<int>::iterator iter;
		for(iter = s_r.begin(); iter != s_r.end(); iter++){
			cout << *iter << " ";
		}
		cout << endl;
	}
}

总结

此题因为运行超时得到了40分,仅为没思路的同学提供一些想法,如果有改进建议欢迎评论!
觉得不错,记得帮忙点个赞哟!

你可能感兴趣的:(c++,算法,开发语言)