PTA-BasicLevel-1003 我要通过!
大一新生,编程菜鸡,仅仅作为个人笔记,轻喷
所用平台:macOS 编程IDE:Xcode
题目详情:“答案正确”是自动判题系统给出的最令人欢喜的回复。本题属于 PAT 的“答案正确”大派送 —— 只要读入的字符串满足下列条件,系统就输出“答案正确”,否则输出“答案错误”。
得到“答案正确”的条件是:
字符串中必须仅有 P、 A、 T这三种字符,不可以包含其它字符;
任意形如 xPATx 的字符串都可以获得“答案正确”,其中 x 或者是空字符串,或者是仅由字母 A 组成的字符串;
如果 aPbTc 是正确的,那么 aPbATca 也是正确的,其中 a、 b、 c 均或者是空字符串,或者是仅由字母 A 组成的字符串。
现在就请你为 PAT 写一个自动裁判程序,判定哪些字符串是可以获得“答案正确”的。
输入格式:
每个测试输入包含 1 个测试用例。第 1 行给出一个正整数 n (<10),是需要检测的字符串个数。接下来每个字符串占一行,字符串长度不超过 100,且不包含空格。
输出格式:
每个字符串的检测结果占一行,如果该字符串可以获得“答案正确”,则输出 YES,否则输出 NO。
具体要求分析
要求输入一个字符串,判断其正确与否
要求如下:
1: 要求输入的字符串有且仅有 P A T 三个字符
2:任何形状入 xPATx (其中x为 仅有一个或多个A组成的字符串,或者是 空字符串 空字符串不等价于空格! 以下不在做解释)
3:如果 aPbTc是正确的,那么 aPbATca 也是正确的。
注意:能否正确理解第三个条件是能否拿满分的关键!
第三个条件分析:
题目中的第三个条件是一个充分条件
(即 如果 p 是正确的 既可以推出 q是正确的 ,以下不做解释)
那么会存在一个问题我们会如何确定p是正确的呢?
那就要用到1,2两个条件,所以第三个条件的作用是将不能直接用1,2条件判断的进行转化(以下把第三个条件称为转化),转化为 1,2可以判断的
那么我们仔细研究一下转化是如何进行的呢?
由条件 我们发现 在往前推的时候
1:a是不变的
2:b少了一个 A
3:c少了一个 a
例如我们要判断一个字符串
APAAATAA
(在本题目中,我们将P称为前面的A,P与T中间的A称为中间的,T后面称为后面的A,以下不在解释)
首先字符串满足 1,但是不满足2,我们开始用3开始转化
我们可以确定 a 是 一个 A
所以 c 是 一个 A
所以有 APAATA > APAAAPAA (其中 > 这个符号代表充分条件)
我们会发现 我们还是无法直接判断 APAATA 这个字符串的正确性,那么也就意味着我们还需要在用一次转化,
APAT > APAATA > APAAATAA
我们发现这个字符串是错的 因为 2要求前后的a的数量相等,而这个例子显然不想等
OK至此,我们已经基本理清楚了如何判断一个字符串是否正确
现在有两种方法来解题:
1:让程序模拟我们的方法,进行判断
2:我们在其中发现规律
实不相瞒在更加复杂的题目题目中1可能是一个更加好的解决方案,但是在本题中我们可以较为容易的得出 前 中 后 三个A的关系
我们不妨假设有 中间有 b 个 A
如果要用条件 2 就必须进行 (b-1)转化
也就是 后面要减去 (b-1)*a 的A
并且做完以后还要 前后数量相等
那么我们就可以得出表达式
c - (b - 1) * a == a
那么大功告成,可以开始写代码了!!!
整体规划
函数声明:
//主函数 复杂输入字符串 调用判断函数 输出等操作
int main();
//判断函数 负责判断字符串对错
int judge(char exam[101]);
主要变量声明
//用于存放输入的字符串 题目中最长为 100 个 我们给101个
char exam[101];
//用于存放长度
int count;
具体过程实现
main 函数
int main(int argc, const char * argv[]) {
//k存放判断例子的多少
int k;
scanf("%d",&k);
//循环判断
for (int i = 0; i < k; i++) {
//清空字符串
memset(exam,'\0',101);
//输入串
scanf("%s",exam);
//求长度
count = (int)strlen(exam);
//利用自定义函数循环求解
if (judge(exam) == 1) {
printf("YES\n");
}else {
printf("NO\n");
}
}
return 0;
}
judge函数
int judge(char exam[101]){
//标识符定义 P,T_signal用于判断是否有P,T。 front_A,...用于统计A的数量分别为前中后
int P_signal = 0,front_A = 0,middle_A = 0,latter_A = 0,T_signal = 0;
for (int i = 0; i < count; i++) {
//判断是否为 P A T
if ((exam[i] != 'P') && (exam[i] != 'A') && (exam[i] != 'T')) {
return 0;
}
//重复P T 是否出现P 和 T
if (exam[i] == 'P' && P_signal) {
return 0;
}
if (exam[i] == 'P' && T_signal) {
return 0;
}
//P T 标识符 P T 出现顺序是否有误
if (exam[i] == 'P') {
P_signal = 1;
}else if(exam[i] == 'T'){
if ((P_signal == 0 )|| (latter_A + middle_A == 0)) {
return 0;
}
T_signal = 1;
}
//统计 前 中 后 A的数量
if ((!P_signal) &&(exam[i] == 'A') && !T_signal) {
front_A ++;
}else if(P_signal && (!T_signal) &&(exam[i] == 'A')){
middle_A ++;
}else if((exam[i] == 'A') && (P_signal && T_signal)){
latter_A ++;
}
}
//没有没有完整的PAT字符串
if (!(P_signal && T_signal && (latter_A + front_A + middle_A))) {
return 0;
//中间只有一个A 且 前面的A数量等于后面的A 那么正确
}else if(middle_A == 1 &&(latter_A == front_A)){
return 1;
//中间大于一个A
}else if(middle_A >= 2){
//如果两边没有 就一定可以
if (front_A + latter_A == 0) {
return 1;
}
//两边有 满足我们给出的表达式就可以
if (latter_A - (middle_A - 1) * front_A == front_A ) {
return 1;
}
}else return 0;
return 0;
}
代码总结:
总体来说代码实现主要基于分析和推倒,在拥有明确思路后解决这个问题并不难,主要难在第三个条件的分析。
代码并不够精剪,希望各位大佬指教
所有代码
//
// main.c
// 1003
//
// Created by LLONVNE on 2021/6/16.
//
#include <stdio.h>
#include <string.h>
char exam[101];
int count;
int judge(char exam[101]){
//标识符定义
int P_signal = 0,front_A = 0,middle_A = 0,latter_A = 0,T_signal = 0;
for (int i = 0; i < count; i++) {
//判断是否为 P A T
if ((exam[i] != 'P') && (exam[i] != 'A') && (exam[i] != 'T')) {
return 0;
}
//重复P T
if (exam[i] == 'P' && P_signal) {
return 0;
}
if (exam[i] == 'P' && T_signal) {
return 0;
}
//P T 标识符
if (exam[i] == 'P') {
P_signal = 1;
}else if(exam[i] == 'T'){
if ((P_signal == 0 )|| (latter_A + middle_A == 0)) {
return 0;
}
T_signal = 1;
}
if ((!P_signal) &&(exam[i] == 'A') && !T_signal) {
front_A ++;
}else if(P_signal && (!T_signal) &&(exam[i] == 'A')){
middle_A ++;
}else if((exam[i] == 'A') && (P_signal && T_signal)){
latter_A ++;
}
}
//没有没有完整的PAT字符串
if (!(P_signal && T_signal && (latter_A + front_A + middle_A))) {
return 0;
//中间只有一个A
}else if(middle_A == 1 &&(latter_A == front_A)){
return 1;
//中间有>@A
}else if(middle_A >= 2){
//如果两边没有 就一定可以
if (front_A + latter_A == 0) {
return 1;
}
//两边有
if (latter_A - (middle_A - 1) * front_A == front_A ) {
return 1;
}
}else return 0;
return 0;
}
int main(int argc, const char * argv[]) {
int k;
scanf("%d",&k);
for (int i = 0; i < k; i++) {
//清空字符串
memset(exam,'\0',101);
//输入串
scanf("%s",exam);
//求长度
count = (int)strlen(exam);
//利用自定义函数循环求解
if (judge(exam) == 1) {
printf("YES\n");
}else {
printf("NO\n");
}
}
return 0;
}