CCF真题网址
题目思路
我的思路较为简单,即对于每个匹配表达式,遍历N个用户,验证是否匹配。
对于每个表达式有两种情况:
对于原子表达式,我们利用编写的函数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()
s.find(str)
find()
返回值是字母在母串中的第一次出现的下标位置。如果没有找到,那么会返回-1
。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;
}
}
题目思路
我的改进主要是参考了这篇文章,我对以上代码的修改仅限于atomic_expression
以及resolve
的返回类型。
对于每个原子表达式,获取符合表达式的LD集合,之后进行交并集操作。
对于代码的一些解释,atomic_expression
函数中index = min(s.find(':'), s.find('~'));
正常情况下s.find(':')
和s.find('~')
必然有一个-1
,另一个>0
,我们想要获取>0
的index
,应该选择max
而不是min
,但是-1
在此函数中对应的是18446744073709551615
,所以需要选择min
。
基础知识补充
map操作
map及set都是通过迭代器进行遍历,区别在于map读取元素的方式为it->first
和it->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分,仅为没思路的同学提供一些想法,如果有改进建议欢迎评论!
觉得不错,记得帮忙点个赞哟!