1003 我要通过! (20 分) C语言 耗时3周...解出来的

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周的周末上午。。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值