CCF201809第三题
博主很懒,题目相信大家自己有,那我就不贴上来啦!(`・ω・´)
先说说自己做题过程中的体会和一些注意点吧:
首先,这题相比其他时候的第三题温柔了不少---我竟然能在10分钟内读懂!接着关于题目内容,核心主要是在与后代选择器的一些细节:
1)标签大小不敏感,id 敏感,所以比较标签时要统一化为大写或小写;
2)因为要获得的是最终的子代行数,子代是主要矛盾点,所以我采用从子代倒推的思路:即先从最后开始找到子代,暂时保留结果,接着往前判断该子代是否符合匹配;
3)还有一点是我当初一直忽略的,是祖先有符合就行,并不一定是刚好上一代~(因为这个,卡了我好久。。。)
4)最后就是常规的用容器来存储去掉空格的信息,这跟之前URL那题一样。
直接上代码啦,因为本人有写注释的习惯,应该不会看得太困难。
部分代码粘过来后缩进有些问题,不好意思。。这个除了自己一行行的调还有什么办法么,求助呀~
如果实在难受,可以到我的cn博客上看,地址:https://www.cnblogs.com/GorgeousBankarian/p/10384463.html
转载注明出处哟~
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>//结果排序
using namespace std;
struct HTML{
int bank;//前导空格数
string name;
string id;
HTML(){
bank=0;
}
}Stand[100];//去空格存储 每行
int n=0,m=0;
string Initial[100];//原始数据
vector<int> Final[10];//10行的向量数组 ,存行
int total[10]={0};//符合的组数;
void Transl(string str,int i)//去空格获信息
{
while(str[0]=='.'){
Stand[i].bank++;//前导空格统计
str.erase(0,1);//删第一个字符
}
while(str[0]!=' '){ //遇间隔跳出
Stand[i].name+=str[0];
str.erase(0,1);
if(str.empty()) {
Stand[i].id="";
break;//无id时
}
}
//有id时
if(!str.empty()) str.erase(0,1);//去掉间隔
Stand[i].id=str;
}
int Count_bank(string judge)//统计间隔,用于待匹配的
{
int count=0;
for(int i=0;i<judge.size();i++)
{
if(judge[i]==' '){
count++;
}
}
return count;
}
string TranName(string str)//全部转换为小写匹配
{
for(int i=0;i<str.size();i++)
{
if(str[i]<='Z'&&str[i]>='A')
{
str[i]+='a'-'A';
}
}
return str;
}
bool Checkid(string str)//判断是否是id
{
if (str[0]=='#') return true;
return false;
}
bool Check_str(int temp_n,string str)//判断是否还有符合的最子代
{
if(Checkid(str)){//匹id
for(int i=temp_n;i>=0;i--)
{
if(Stand[i].id==str) return true;
}
return false;
}
else
{//匹name
for(int i=temp_n;i>=0;i--)
{
if(TranName(str)==TranName(Stand[i].name)) return true;
}
return false ;
}
}
int main()
{
cin>>n>>m;
cin.get();
int i=0,j=0;
for(i=0;i<n;i++)
{
getline(cin,Initial[i]);//原始数据
Transl(Initial[i],i);
}
string judge;//要匹配的
int ti=0;//第几个待匹配
int temp_m=m;
while(temp_m--)
{
getline(cin,judge);
int count=Count_bank(judge);//统计间隔
if(count==0)//单个元素
{
for(i=0;i<n;i++)
{
if(TranName(judge)==TranName(Stand[i].name)||judge==Stand[i].id)
{
total[ti]++;
Final[ti].push_back(i+1);//存行
}
}
}
else if(count>0)//多个元素
{
count++;//元素个数
string tran[100];
string temp_str;
//先去间隔
i=0;
while(!judge.empty())
{
if(judge[0]!=' '){
temp_str+=judge[0];
judge.erase(0,1);
}
else{//==' '
judge.erase(0,1);
tran[i]=(temp_str);
i++;
temp_str.clear();
}
}
tran[i]=(temp_str);//得到待匹配的信息
//开始匹配从子代反推
int temp_n=n-1;
int temp_bank=0;
int temp_line=0;
while(Check_str(temp_n,tran[count-1]))
{
int judgenum=0;//统计匹配数
for(j=count-1;j>=0;j--)//逐个匹配
{
bool flag=Checkid(tran[j]);
for(i=temp_n;i>=0;i--)
{
if(flag)
{//匹id
if(tran[j]==Stand[i].id)
{
if(j==count-1)
{//最子代
judgenum++;
temp_n=i-1;//下一次起始顺前
temp_bank=Stand[i].bank-2;//初始子代的前导空格
temp_line=i+1;
break;//匹配则跳出
}
else{ //非最子代
if(Stand[i].bank<=temp_bank){//前导空格匹配
temp_bank=Stand[i].bank-2;
judgenum++;
break; //匹配
}
else continue;
}
}
}
else
{//匹name
if(TranName(tran[j])==TranName(Stand[i].name))
{
if(j==count-1)
{//最子代
judgenum++;
temp_n=i-1;//下一次起始顺前
temp_bank=Stand[i].bank-2;//初始子代的前导空格
temp_line=i+1;
break;//匹配则跳出
}
else
{ //非最子代
if(Stand[i].bank<=temp_bank){//前导空格匹配 是祖先即可
temp_bank=Stand[i].bank-2;
judgenum++;
break; //匹配
}
else continue;
}
}
}
}
}
if(judgenum==count)
{
total[ti]++;
Final[ti].push_back(temp_line);
}
}
}
ti++;
}
for(i=0;i<m;i++)
{
cout<<total[i]<<' ';
sort(Final[i].begin(),Final[i].end());
for(j=0;j<Final[i].size();j++)
{
cout<<Final[i][j]<<' ';
}
cout<<endl;
}
return 0;
}