题目描述:
小A的英语考了个不及格,老师很生气,并且发现他英语的语法几乎全错!于是老师决定好好教教他英语语法。
老师想先从句子结构开始教他。一个句子至少需要包含主谓结构,即主语和谓语,并且主语在前,谓语在后。
有些句子会在谓语后面加上宾语。避免复杂,本题中句子的顺序严格按照主语-谓语-宾语的顺序(即无宾语前置和倒装等情况)。
老师给了小A三张单词表,分别是主语单词表、谓语单词表和宾语单词表。老师要让小A用这些单词表中的单词来造句,
并且规定:谓语有且仅有一个单词,主语和宾语可以包含任意个单词(主语不可为空)。
老师暂时不想让小A造出能保证意思通顺的句子,他只想让小A能够学会基本的句子结构就行。
现在,小A根据这些单词造了m条句子,现在假设你是老师,你需要判断每条句子是否符合上述句子结构。
输入描述
第一行三个正整数n1,n2,n3,分别表示主语、谓语、宾语单词表的单词数;
第二行包含n1个单词,单词仅由小写英文字母组成,每两个单词之间有一个空格,单词长度不超过10;
第三行包含n2个单词,其他格式同上;
第四行包含n3个单词,其他格式同上;
第五行一个正整数m;
接下来m行,每行一个句子。句子由若干单词(至少一个)组成,并且保证出现的单词都在上面的单词表内。每两个单词之间一个空格隔开。
数据保证一个单词最多只可做一种句子成分。即每个单词仅会出现在一个单词表上。
1≤n1,n2,n3≤1000,1≤m≤20,1≤句子单词数≤10
输出描述
对于每条句子,如果其符合句子结构,输出一行“YES”(不含引号),否则输出一行“NO”(不含引号)。
样例输入
3 3 3
i you he
am is are
yours his hers
5
i am yours
you is his
he are hers yours
i am am yours
is his
样例输出
YES
YES
YES
NO
NO
用C++代码实现,思路:把主谓宾用unordered_set<string>放起来,方便查找。然后把每个句子都拆成单词放入vector<vector<string>>中。输入完后,处理每一个句子看是那种情况,输出”NO”,”YES”.
代码如下:
#include <bits/stdc++.h>
using namespace std;
int main(void)
{
int n1 = 0, n2 = 0, n3 = 0, m = 0;
unordered_set<string> s1; // 主语
unordered_set<string> s2; // 谓语
unordered_set<string> s3; // 宾语
cin >> n1;
cin >> n2;
cin >> n3;
string temp;
for(int i = 0; i < n1; i++) {
cin >> temp;
s1.insert(temp);
}
for(int i = 0; i < n2; i++) {
cin >> temp;
s2.insert(temp);
}
for(int i = 0; i < n3; i++) {
cin >> temp;
s3.insert(temp);
}
cin.clear();
cin >> m;
// cout << endl << "m : " << m << ", s1.size(): " << s1.size() << ", s2.size(): " << s2.size() << ", s3.size(): " << s3.size() << endl;
cin.get(); // 去掉换行
vector< vector<string> > v;
for(int i = 0; i < m; i++) { // m个句子输入
vector<string> vTemp;
char c;
temp.clear();
c = cin.get();
while( c != '\n' ) {
if(c == ' ' ) {
// cout << temp;
vTemp.push_back(temp);
temp.clear();
}
else {
temp += c;
}
c = cin.get();
}
vTemp.push_back(temp);
v.push_back(vTemp);
// getline(cin, temp); //行读取
// v[i] = temp;
}
// 调试代码,看句子输入是否正确
// cout << endl;
// for(int i = 0; i < m; i++) {
// for( int j = 0; j < v[i].size(); j++){
// cout << v[i][j] << " " ;
// }
// cout << endl << "111\n";
// }
// cout << endl;
// 现在开始处理数据
for(int i = 0; i < m; i++) {
if(v[i].size() == 0)
{
cout << "NO" << endl;
continue;
}
int s = v[i].size(); // 一行的元素大小
int zhu = 0, wei = 0, bing = 0; // 主谓宾个数
for(int j = 0; j < s; j++) {
if( s1.find(v[i][j]) != s1.end() ) { // 主语
zhu++;
} else if(s2.find(v[i][j]) != s2.end()) {
wei++;
if( (wei == 1 && zhu == 0) || wei == 2) { // 没主语有谓语 和 两个谓语的情况
cout << "NO" << endl;
break;
}
} else if(s3.find(v[i][j]) != s3.end()) {
bing++;
if(zhu == 0 && wei == 1 && bing == 1) { // 没主语有谓语和宾语
cout << "NO" << endl;
break;
}
}
if(j == s-1) {
cout << "YES" << endl;
}
}
}
return 0;
}
**复盘总结:**我把输入的cin和getline的具体用法忘记了,调试了半天没弄对。晚上做该题总结:
-
cin 后用cin.get(),getline() 的问题(已经翻车两次了,输入老有问题):
用cin会自动忽略换行,然后再用其他函数读。情况1:用cin.get()直接读数据会读到一个换行,需要用一个cin.get()把换行读出来再用cin.get()去读数据;情况2:用getline也会出现读到换行符的情况。 -
cin.get读取一个字符
可以使用cin.get()
或者cin.get(var)
两种方式,可以读出一个字符(空格,换行等)。 -
cin.get 读取一行,缓冲区还有一个换行符不被清理
可以用istream& get(char* s, streamsize n)
或者istream& get(char* s, size_t n, streamsize delim)
区别前者默认以换行符结束,后者可以指定结束符; n表示目标空间的大小。可以用cin.get()或者cin.ignore()来清理 -
cin.getline读取一行,会自动清理缓冲区的换行符
istream& getline(char* s, streamsize count);
istream& getline(char* s, streamsize count, char delim);
#include<iostream>
using namespace std;
int main(void)
{
char a;
char array[20] = {NULL};
// 输入123456789换行时
// cin.get(array, 20); // 123456789
// cin.get(a); // 读换行
// cout << array << " " << (int)a << endl; // 123456789 10
// 输入123456789换行换行 注意两个换行才能读到a的换行
cin.getline(array, 20); // cin.getline(array, 20, '\n');
cin.get(a);
cout << array << " " << (int)a << endl; // 123456789 10
return 0;
}
- getline读取一行,在std命名空间的全局函数,参数使用了string字符串。
getline利用cin可以从标准输入设备键盘读取一行,当遇到如下三种情况结束读操作:
1)到文件结束
2)遇到函数的定界符
3)输入达到最大限度
istream& getline(istream& is, string str);
istream& getline(istream& is, string str, char delim);
6.申请vector<vector<string>> v(m)
,然后后边用v.push_back(temp)
放数据,导致前面数据没放对位置;正确应该是v[i] = temp
。