发表在专栏“PAT乙级题目详解”,并在持续更新中。
https://blog.csdn.net/column/details/23947.html
“答案正确”是自动判题系统给出的最令人欢喜的回复。本题属于PAT的“答案正确”大派送 —— 只要读入的字符串满足下列条件,系统就输出“答案正确”,否则输出“答案错误”。
得到“答案正确”的条件是:
1. 字符串中必须仅有P, A, T这三种字符,不可以包含其它字符;\
现在就请你为PAT写一个自动裁判程序,判定哪些字符串是可以获得“答案正确”的。
输入格式: 每个测试输入包含1个测试用例。第1行给出一个自然数n (<10),是需要检测的字符串个数。接下来每个字符串占一行,字符串长度不超过100,且不包含空格。
输出格式:每个字符串的检测结果占一行,如果该字符串可以获得“答案正确”,则输出YES,否则输出NO。
分析:
看到这个题目,首先是从“A”“P”“T”的位置和数量分析,
1.假设left表示“P”的数量,显然“P”的数量有且只有一个;P的前面应该是没有或者仅有“A”;
2.mid表示中间的“A”的数量,mid的数量也要大于等于1;
3.right表示“T”的数量,right的数量应该为1.right的前面是“P”和“A”,并且“P”和“T”之间至少有一个“A”(即mid == 1)。
#include
#include
using namespace std;
int main()
{
int n;
cin >> n;
string test;
int l = 0;//输入的字符串的长度
for (int i = 0; i < n; i++)
{
int left = 0;//记录左边的"P"出现的次数
int mid = 0;//记录中间的"A"出现的次数
int right = 0;//记录右边的"T"出现的次数
//输入一个字符串,判断
cin >> test;
l = test.size();
//遍历字符串中的每一个字母
for (int j = 0; j < l; j++)
{
////如果出现了非法字符,直接输出“NO”,并结束
if (test[j] != 'P' && test[j] != 'A' && test[j] != 'T' && test[j] != ' ')
{
//cout << "NO" << endl;
break;
}
//如果当前字符是"A",则继续循环,知道找到"P"
if (test[j] == 'A')
{
if (left == 1)
{
mid++;
}
continue;
}
//如果当前字符是"P",
if (test[j] == 'P')
{
left++;
continue;
}
//如果当前字符是"T"
if (test[j] == 'T')
{
if (mid >= 1)
{
right++;
}
continue;
}
}
if (left == 1 && right == 1 && mid >= 1)
{
cout << "YES" << endl;
}
else
{
cout << "NO" << endl;
}
}
system("pause");
return 0;
}
这种思路只能通过前面的7个测试,“APAAATAA”这种情况不通过。
仔细想一下,应该“如果 aPbTc 是正确的,那么 aPbATca 也是正确的,其中 a, b, c 均或者是空字符串,或者是仅由字母 A 组成的字符串。”这句话的问题。
(1)这句话说的是任意满足条件的aPbTc正确,则可以得到另外一个正确的表达式aPbATca。
(2)那么最简单的正确的表达式是PAT(b的初始值是A),可以得到PAAT也是正确的,延伸出PAAAT正确。
(3)在第(2)条是在“a”和“c”为空的情况下得到的,那么在“a”“c”赋值的情况下,假设“a” “c”都为“A”,那么“APATA”是正确的,可以得到“APAATAA”也是正确的,延伸出“APAAATAAA”也是正确的,到这,是不是发现了一些规律呢?还没有发现吗,好吧,再来看
(4)“a”赋值“A”c赋值“AA”(这样设置的原因是在第(3)条中“a”和“c”设置的是一样的,所以在本条中希望设置的不一样,以体现规律的适用性),最简单的是“APAATAA”,可以得到“APAAATAAA”.可能有人会疑问为什么在“a”赋值“A”c赋值“AA”的情况下,最简单的不是“APATAA”呢?因为如果把它写成“aPbATca”形式,找不到一个“aPbTc”形式来验证它的正确性。
(5)得出结论,每一次的延伸,b都是多了一个“A”,同时“ca”也是“a”的翻倍,所以可以得到结论a*b = c,符合这个条件的就是对的,不符合就是错的。
(6)原来这个题目看起来这么难,分析到最后,仅仅是一个找规律的题目而已啊。生活中有很多看似很难的事情,多尝试一下,同样可以成功的!!!
好了,不多说了,附代码:
#include
#include
using namespace std;
int main()
{
int n;
cin >> n;
string test;
int l = 0;//输入的字符串的长度
for (int i = 0; i < n; i++)
{
int left = 0;//记录左边的"A"出现的次数
int mid = 0;//记录中间的"A"出现的次数
int right = 0;//记录右边的"A"出现的次数
int t = 0;//记录T出现的次数
int p = 0;//记录P出现的次数
//输入一个字符串,判断
cin >> test;
l = test.size();
//遍历字符串中的每一个字母
for (int i = 0; i < l; i++)
{
////如果出现了非法字符,结束
//if (test[j] != 'P' && test[j] != 'A' && test[j] != 'T' && test[j] != ' ')
//{
// //cout << "NO" << endl;
// break;
//}
//计算"P"之前的"A"的数目,之前一定要没有出现过"P"
if (test[i] == 'A' && p == 0 && t == 0)
{
left++;
continue;
}
//计算"P"的数目,
if (test[i] == 'P')
{
p++;
continue;
}
//计算中间的"A"的数目,之前一定要出现一个"P",并且只能出现这一个
if (test[i] == 'A' && p == 1 && t == 0)
{
mid++;
continue;
}
//计算"T"的数目,"T"之前必定要出现"A"
if (test[i] == 'T' && mid >= 1)
{
t++;
continue;
}
//计算后面的"A"的数目,之前一定要出现一个"T"
if (test[i] == 'A' && p == 1 && t == 1)
{
right++;
continue;
}
else
{
break;
}
}
//结束并判断
//
if (p == 1 && t == 1 && left * mid == right)
{
cout << "YES" << endl;
}
else
{
cout << "NO" << endl;
}
}
system("pause");
return 0;
}