题解:P10788 [入门赛 #25] sql

· · 题解

题意

简化题意:输入每张表格,并用语句查询表格内容。

$m$ 次 sql 语句查询,格式是 `select [columns] from [table_name] where [header]=x`,输出在 `table_name` 这张表格里,`header` 这一表头的**这一列中**值为 `x` 的那一行的 **`columns` 列的值,且 `columns` 里可能有多个要输出的表头名。** ## 分析 数据范围很小,主要思路是**模拟**。 我们可以定义如下数组。 ```cpp string name[11],title[11][11],excel[11][101][11]; int xx[11],yy[11]; ``` 以上分别记录每个表格名字,每个表格的表头,每张表格除第一行(也就是除去表头)的内容,每张表格的长度 $x$ 和宽度 $y$。 这样一来,输入的问题就解决了。 如何查询呢?我们可以编写函数分别查找一个表格名字是第几个,一个表头在每张表格里的第几列。 输入字符串,截取每个字符串的有用部分。 可以用 cstring 库中带有的 substr() 函数来进行截取,比较方便。 对于可以输入多个表头名的 `columns`,我们可以记录一下其中逗号出现的位置,这样模拟会比较方便。特殊的,要判断一下没有逗号出现的情况。 完成上述预备环节之后,就可以愉快地枚举了。 可以参考下面的代码。 ## Code ```cpp #include<bits/stdc++.h> using namespace std; #define int long long string name[11],title[11][11],excel[11][101][11];//表格名字,每张表的表头,表格整体内容 int xx[11],yy[11],d[150];//每张表的x,y长度 & 逗号出现的位置 int n;//n张表 int f1(string a){ //返回是第几个表格的名字 for(int i=1;i<=n;i++){ if(name[i]==a) return i; } } int f2(int a,string b){ //第a个表中的 b表头的纵坐标 for(int i=1;i<=yy[a];i++){ if(title[a][i]==b) return i; } } void put(int a,int b,int c){ //输出内容 cout<<excel[a][b][c]<<" "; return; } signed main(){ cin>>n; for(int i=1;i<=n;i++){ cin>>name[i];//输入表格名字 int x,y;cin>>x>>y; for(int j=1;j<=y;j++) cin>>title[i][j];//先单独输入表头在title数组,方便判断 x--,xx[i]=x,yy[i]=y; //除去表头这一行,剩下 x-1 行 for(int j=1;j<=x;j++){ for(int k=1;k<=y;k++){ cin>>excel[i][j][k]; } } } int m;cin>>m; for(int i=1;i<=m;i++){ //select [columns] from [table_name] where [header]=x string out;cin>>out>>out;//记录 `columns` int len=0;//记录多少个逗号 memset(d,0,sizeof(d));//初始化 for(int j=0;j<out.size();j++) if(out[j]==',') d[++len]=j; string which;cin>>which>>which;//记录 `table_name` int num=f1(which);//调用函数查询是第几个表格的名字 string tmp;cin>>tmp>>tmp; int tmp1=tmp.find('=');/*查找等号出现的位置*/ string pd1=tmp.substr(0,tmp1),pd2=tmp.substr(tmp1+1);//截取 int num2=f2(num,pd1);//查询表头是第几列,方便枚举 for(int j=1;j<=xx[num];j++){ if(excel[num][j][num2]==pd2){//找到了符合条件的 if(len==0){ //特判单个表头名的 put(num,j,f2(num,out)); }else{ for(int k=1;k<=len+1;k++){ string awa; if(k==1) awa=out.substr(0,d[k]); else if(k==len+1) awa=out.substr(d[k-1]+1); else awa=out.substr(d[k-1]+1,d[k]-d[k-1]-1); put(num,j,f2(num,awa)); //上述是推出来的截取计算式 //k==1 0,d[k] //k==2 d[k-1]+1,d[k]-d[k-1]-1 //k==len+1 d[k-1]+1 } } printf("\n"); } } } return 0;//good habit~ } ``` 下面补充一下上面的代码中出现的在 cstring 库中的函数的使用方法。 ```cpp #include<cstring> #include<iostream> using namespace std; int main(){ string a="abcd"; //a.substr(x,y) 截取字符串 a 从下标 x 位置开始,连续的 y 个字符 cout<<a.substr(0,2)<<endl;//输出 `ab` cout<<a.substr(1)<<endl;//若没有传进 y,默认从下标 x 位置开始截取到末尾,输出 `bcd` //a.find(x) 返回 x 在 a 中的位置(下标从0开始) cout<<a.find('d')<<endl;//输出3 return 0; } ```