1.题目
1003 我要通过! (20 分)
“答案正确”是自动判题系统给出的最令人欢喜的回复。本题属于 PAT 的“答案正确”大派送 —— 只要读入的字符串满足下列条件,系统就输出“答案正确”,否则输出“答案错误”。
得到“答案正确”的条件是:
1.字符串中必须仅有 P、 A、 T这三种字符,不可以包含其它字符;
2.任意形如 xPATx 的字符串都可以获得“答案正确”,其中 x 或者是空字符串,或者是仅由字母 A 组成的字符串;
3.如果 aPbTc 是正确的,那么 aPbATca 也是正确的,其中 a、 b、 c 均或者是空字符串,或者是仅由字母 A 组成的字符串。
现在就请你为 PAT 写一个自动裁判程序,判定哪些字符串是可以获得“答案正确”的。
输入格式:
每个测试输入包含 1 个测试用例。第 1 行给出一个正整数 n (<10),是需要检测的字符串个数。接下来每个字符串占一行,字符串长度不超过 100,且不包含空格。
输出格式:
每个字符串的检测结果占一行,如果该字符串可以获得“答案正确”,则输出 YES,否则输出 NO。
输入样例:
8
PAT
PAAT
AAPATAA
AAPAATAAAA
xPATx
PT
Whatever
APAAATAA
输出样例:
YES
YES
YES
YES
NO
NO
NO
NO
2.反思该题字符串的难点
2.1题目的逻辑很难,很难理解
-
第一个条件还好。
-
第二个条件需要注意:1."PAT"连在一起出现 2."PAT"左右两边字符对称 3.'P’与’T’只出现一次。
-
第三个条件,是基于符合第二个条件的结果推出来的。
-
第一类,根据"PAT"推出来的,就是"PAT"(符合第二个条件也就符合第三个条件的如果) 推出 "PAAT"推出"PAAAT"推出…
-
第二类,根据 “…PAT…” 推出来的,举例就是
‘’APATA"(符合第二个条件也就符合第三个条件的如果) 推出 “’APAATAA” 推出 “APAAATAAA” 推出 …
“AAPATAA” (符合第二个条件也就符合第三个条件的如果) 推出 “AAPAATAAAA” 推出 “AAPAAATAAAAAA”
-
处理方法与注意:
-
处理第二类的方法:写几个数找规律:(1)P之前的A的个数始终不变 (2)中间的A多一个,那么T后面的就要多一个 P之前的字符串。
所以最后找到的规律是 (’T‘后面的’A’的个数 - ’P‘前面的’A’的个数)/ ’P‘前面的’A’的个数 =='P’与’T’之间的’A’的个数-1
化简一下,就是 'P’与’T’之间的’A’的个数 == (’T‘后面的’A’的个数/ ’P‘前面的’A’的个数)
-
注意:'P’与’T’只出现一次
-
-
思考,为什么“PT”是错的?因为 "PT"不满足第二条,也就不满足第三条的如果,也就推不出来了。
2.2 每个条件对应的处理函数
处理条件1:
处理条件2:
用到了strstr()找字串"PAT"的位置,返回来的是字符指针或者NULL。
处理条件3:
3.AC代码
#include<stdio.h>
#include<string.h>
int isAllPAT(char *str){
int i=0;
int countT=0,countP=0;
for(i;i<strlen(str);i++){
if(str[i]=='A'||str[i]=='P'||str[i]=='T'){
if(str[i]=='P') countP++;
if(str[i]=='T') countT++;
continue;
} else{
return 0;
}
}
if(countP==1 && countT==1)//非常重要的判断
return 1;
else return 0;
}
int isPAT(char * str){
char *pos;
pos=strstr(str,"PAT");
if(pos==NULL){
return -1;
}
else{//判断"PAT"两边的字符串是否对称
int delt1=pos-str;//左边
int delt2=strlen(str)-(pos-str+3);//右边
if(delt1==delt2){
return pos-str;//偏移量。
}
else return -1;
}
}
int isThird(char *str){
int p,t;
int before=0,center=0,after=0;
int i,j;
for(i=0;i<strlen(str);i++){
if(str[i]=='P' ){
for(j=i+1;str[j]!='T';j++){
center++;
}
i=j+1;
}
if(center==0&&str[i]=='A'){
before++;
}
if(center>0&&str[i]=='A'){
after++;
}
}
if(center==0) return 0;
if(after==before) return 1;
//处理前半段和后半段字符中A的数量不相等。
if((after-before)/before==(center-1)){
return 1;
}return 0;
}
int judge(char *str){
if(isAllPAT(str)==0){
return 0;
}
if(isPAT(str)!=-1){
return 1;
}
if(isThird(str)==1) return 1;
return 0;
}
int main(){
int n;
int i;
char str[100];
memset(str,0,strlen(str));//
scanf("%d",&n);
for(i=0;i<n;i++){
getchar();
scanf("%s",str);//直接输入%s 1.忽略前导空白字符 2.遇到空格就结束。 如果用scanf("%[^\n]",str); 更严密些,当然%s也不会错。
if(judge(str)==1){
printf("YES\n");
}else{
printf("NO\n") ;
}
}
return 0;
}
做出来耗时:连续3周的周末上午。。。