C语言PAT刷题 - 1003 我要通过!

作者的话:若有朋友复制代码去PAT试着运行遇到问题的:
1.可能是格式问题,可以先把从本站复制的代码粘贴到记事本,再把记事本里的代码复制,然后粘贴到PAT的代码区,提交本题回答,应该就可以了;
2.可能是注释原因,PAT有时候检测到注释会编译错误,所以可以先把注释删了,再进行提交回答。
3.可能是作者当初根据题目写出来的代码仍存在一些疏漏,而恰好当时的测试机制没那么完善,没检测出问题。后面测试机制有所更新,故发现问题,若有相关需要的可以评论区留言或私信作者,我看到的话会去再查一下疏漏之处,然后更新文章。

一、题目描述
“答案正确”是自动判题系统给出的最令人欢喜的回复。本题属于 PAT 的“答案正确”大派送 —— 只要读入的字符串满足下列条件,系统就输出“答案正确”,否则输出“答案错误”。

得到“答案正确”的条件是:
1.字符串中必须仅有 P、 A、 T这三种字符,不可以包含其它字符;
2.任意形如 xPATx 的字符串都可以获得“答案正确”,其中 x 或者是空字符串,或者是仅由字母 A 组成的字符串;
3.如果 aPbTc 是正确的,那么 aPbATca 也是正确的,其中 a、 b、 c 均或者是空字符串,或者是仅由字母 A 组成的字符串。
现在就请你为 PAT 写一个自动裁判程序,判定哪些字符串是可以获得“答案正确”的。
输入格式:
每个测试输入包含 1 个测试用例。第 1 行给出一个正整数 n (≤10),是需要检测的字符串个数。接下来每个字符串占一行,字符串长度不超过 100,且不包含空格。
输出格式:
每个字符串的检测结果占一行,如果该字符串可以获得“答案正确”,则输出 YES,否则输出 NO。
输入样例
10
PAT
PAAT
AAPATAA
AAPAATAAAA
xPATx
PT
Whatever
APAAATAA
APT
APATTAA

输出样例
YES
YES
YES
YES
NO
NO
NO
NO
NO
NO

二、解题思路
读题:
这道题希望我们设计一个自动判题系统,读入一个字符串,满足条件则输出“答案正确”(本题实际是让我们输出YES),否则输出“答案错误”(实际输出NO)。
输入输出都是简单的,所以本题难点在于如何设计代码对相应条件进行检测。接下来我们先来看正确条件:
根据条件第一条我们可以知道,字符串必须有且仅有P、A、T三种字符,不然就是NO。 根据第二条,xPATx形式的字符串是正确的,x可以是空字符串(就是啥都没有,不要和空格混淆哦),也可以是仅由字母A组成的字符串(也就是若干个A),细化一下,它的形式就是1.PAT 2.XPATX (注:这里的X代表若干个A,并且至少为1个A)(特别注意,这里X代表若干个A,PAT两边都是X,也就是说,按照第二种正确形式,PAT两边A的个数必须一样)。
第三条,如果aPbTc是正确的,那么aPbATca也是正确的。也就是说,如果前者是正确的,把它根据后者的形式修改一下得到新的字符串,他也是符合条件的。目前已知的正确形式有两种,也就是条件2的两种:1.PAT 2.XPATX。分别来讨论一下,如果是第一种形式——PAT,根据条件三,可以知道,a、c为空字符串,b为A,整一下容,PAAT也是符合条件的,此时a、c仍为空字符串,b为AA,整一下容,可知PAAAT也是正确的。按此类推,PXT都是对的(前面说过,我把X看做若干个A,且A的数量大于0)。如果是第二种形式——XPATX,根据条件三,可知a、c都是X,b是A,整容一下,XPAATXX是正确的,继续整容,XPAAATXXX也是正确的。以此类推,可以看出一个规律,如果P前面的A的个数乘以P、T中间的A的个数等于T后面的A的个数,那么这个字符串就是符合条件的。
总结,字符串正确的条件是1.字符种类:P、A、T 2.字符串形式:PXT、XPYTZ(X、Y、Z代表若干个A,X、Y至少代表1个A,Z为X中A的个数乘以Y中A的个数)。观察可以发现,PXT形式即P前面没有A,P、T中间至少有一个A,T后面没有A,可以用第二种形式XPYTZ把它看成X=Z=0,Y至少代表一个A,如此计算X乘以Y仍然等于Z,所以可以把两种形式结合,可以得到更为简洁的正确形式:xPYTz(x,z代表若干个A,数目可以为0)。
以上条件通过程序思路可以看成几个判断条件:
1.只能出现P、A、T三种字符
2.P、T的数目为1
3.P比T先出现
4.P前面的A的数目乘以P、T中间的A的个数等于T后面的A的个数
(即x*Y==z且x、z可以为0,Y至少为1)

思路:
1.定义需要的变量(实际解题时是先定义认为需要用到的变量,后面遇到问题需要新定义变量时再回到上头来定义新的变量),从键盘接收一个正整数存入变量n中;
2.定义一个循环来接收多个字符串,一层循环接收一个字符串;
3.定义一个内层循环以对单个字符串中的字符逐个检测,每一轮循环对应一个字符,循环条件为字符’\0’(因为C语言中的字符串默认’\0’为结束符号,当检测到’\0’,就代表字符串结束了),循环体中为根据正确条件设置的判断语句(具体思路在下一步);
4.根据总结后的条件1——只能出现P、A、T三种字符,可以设置if-else if-else形式的分支语句,分别判断当前字符c是否为字符’P’、’A’、’T’或是其他字符,然后执行相应的语句。根据条件2——P、T的数目为1,可以在c为P/T的分支中设置相应变量,计算P/T出现的次数,并设置判断语句判断P/T是否大于1,一旦大于1,就给result的第i个元素(代表第几个字符串)赋值0,即表示当前字符串不符合条件,然后结束循环,不再进行多余的检测,并新设一个循环接收完当前字符串剩下的字符。根据条件3——P比T先出现,在c=’T’的分支中新设置一个判断,如果c=’T’的时候,P的个数为0,即P比T晚出现,就给result的第i个元素(代表第几个字符串)赋值0,即表示当前字符串不符合条件,然后结束循环,不再进行多余的检测。根据条件4——P前面的A的数目乘以P、T中间的A的个数=T后面的A的个数(即x*Y==z且x、z可以为0,Y至少为1),首先要计算x、Y、z的值,所以在c=’A’的时候设置判断,若c=’A’时,P的个数为0,代表这是出现在P前面的A,x++;若P的个数不为0,T的个数为0,代表这个A在P、T中间,Y++;剩下的,自然就是A在T之后,z++。在进行完整个字符串的接收后,设置判断语句判断Y的个数是否>0(因为Y必须为大于0的数),p、t是否为1(前面也设置过循环,当p、t>1时直接result[i]=0,但那个判断必须首先检测到c=’p’/’t’后才会执行,无法排除p/t=0的情况,所以我们在这里补充判断一下),x,Y,z是否满足乘积关系;
5.字符串的检测结束后,根据之前得到的result[i]选择输出”YES”还是”NO”。

三、具体实现
0.标准C源程序框架

#include <stdio.h>
int main()
{
	return 0;
}

1.定义需要的变量(实际解题时是先定义认为需要用到的变量,后面遇到问题需要新定义变量时再回到上头来定义新的变量),从键盘接收一个正整数存入变量n中;

	int n = 0;//存储待检测字符串个数的变量
	int i = 0;//外层循环的循环变量
	char c = 0;//用以接收字符串的一个字符
	int p = 0;//表示P的个数
	int t = 0;//表示T的个数
	int x = 0;//表示P前面的A的个数
	int Y = 0;//表示P、T之间的A的个数
	int z = 0;//表示T后面的A的个数
	int result[10] = {1,1,1,1,1,1,1,1,1,1};//存储代表每个字符串正确性结果的数组,1为正确,0为错误,开始默认每个字符串都是正确的,后面检测到问题,再赋值0
	scanf("%d",&n);
	/*计算机接收内容不是直接接收的,而是先把键盘输入的东西存到输入缓冲区,等检测到回车再一起存入变量n中,而回车作为符号依然留在输入缓冲区,由于我们后面还要接收字符,这里的回车会对后面产生干扰,所以我们在这里设置一个字符读入函数getchar()来接收输入缓冲区的回车。*/
	getchar();

2.定义一个循环来接收多个字符串,一层循环接收一个字符串;

	//1.设置一个循环 - 用以对多个字符串轮流进行检测 - 每一轮循环对应一次检测
	for (i = 0; i < n; i++)
	{
		//对一个字符串的检测操作
	}

3.定义一个内层循环以对单个字符串中的字符逐个检测,每一轮循环对应一个字符,循环条件为字符’\0’(因为C语言中的字符串默认’\0’为结束符号,当检测到’\0’,就代表字符串结束了),循环体中为根据正确条件设置的判断语句(具体思路在下一步);

		//每个字符串的检测都要用到以下变量,所以每次检测新的字符串前要重置这些变量的值,排除干扰
		p = 0;//表示P的个数
		t = 0;//表示T的个数
		x = 0;//表示P前面的A的个数
		Y = 0;//表示P、T之间的A的个数
		z = 0;//表示T后面的A的个数
		while ((c = getchar()) != '\n')
		{
			//对单个字符的判断操作
		}

4.根据总结后的条件1——只能出现P、A、T三种字符,可以设置if-else if-else形式的分支语句,分别判断当前字符c是否为字符’P’、’A’、’T’或是其他字符,然后执行相应的语句。根据条件2——P、T的数目为1,可以在c为P/T的分支中设置相应变量,计算P/T出现的次数,并设置判断语句判断P/T是否大于1,一旦大于1,就给resulti赋值0,即表示当前字符串不符合条件,然后结束循环,不再进行多余的检测,并新设一个循环接收完当前字符串剩下的字符。根据条件3——P比T先出现,在c=’T’的分支中新设置一个判断,如果c=’T’的时候,P的个数为0,即P比T晚出现,就给resulti赋值0,即表示当前字符串不符合条件,然后结束循环,不再进行多余的检测。根据条件4——P前面的A的数目P、T中间的A的个数==T后面的A的个数(即xY==z且x、z可以为0,Y至少为1),首先要计算x、Y、z的值,所以在c=’A’的时候设置判断,若c=’A’时,P的个数为0,代表这是出现在P前面的A,x++;若P的个数不为0,T的个数为0,代表这个A在P、T中间,Y++;剩下的,自然就是A在T之后,z++。在进行完整个字符串的接收后,设置判断语句判断Y的个数是否>0(因为Y必须为大于0的数),p、t是否为1(前面也设置过循环,当p、t>1时直接result[i]=0,但那个判断必须首先检测到c=’p’/’t’后才会执行,无法排出p/t=0的情况,所以我们在这里补充判断一下),x,Y,z是否满足乘积关系;

		while ((c = getchar()) != '\n')
		{
			if (c == 'P')   
			{
				p++;
				if ((p > 1))
				{
					result[i] = 0;
					break;
				}
			}
			else if (c == 'T')
			{
				t++;
				if ((t > 1) || (p == 0))
				{
					result[i] = 0;
					break;
				}
			}
			else if (c == 'A')
			{
				if (p == 0)
				{
					x++;
				}
				else if (t == 0)
				{
					Y++;
				}
				else
				{
					z++;
				}
			}
			else
			{
				result[i] = 0;
				break;
			}
		}
		if (result[i] == 0)
		{
			while ((getchar()) != '\n')
			{
				;
			}
		}
		if ((Y == 0)||(p!=1)||(t!=1))
		{
			result[i] = 0;
		}
		if (x * Y != z)
		{
			result[i] = 0;
		}
	}

5.字符串的检测结束后,根据之前得到的result[i]选择输出”YES”还是”NO”。

	for (i = 0; i < n; i++)
	{
		if (result[i])
		{
			printf("YES");
		}
		else
		{
			printf("NO");
		}
		if (i != (n - 1))   //如果i!=(n-1),即当前不是最后一个待接收的字符串,输出换行符进行换行
		{	//最后一个字符串打印完正确性结果后则不再打印换行符进行换行,从而与输入输出样例保持一致
			printf("\n");
		}
	}

四、全部代码

#include <stdio.h>
int main()
{
	int n = 0;//存储待检测字符串个数的变量
	int i = 0;//外层循环的循环变量
	char c = 0;//用以接收字符串的一个字符
	int p = 0;//表示P的个数
	int t = 0;//表示T的个数
	int x = 0;//表示P前面的A的个数
	int Y = 0;//表示P、T之间的A的个数
	int z = 0;//表示T后面的A的个数
	int result[10] = {1,1,1,1,1,1,1,1,1,1};//存储代表每个字符串正确性结果的数组,1为正确,0为错误
	scanf("%d",&n);
	//printf("数字接收");  //可以用这两个语句来证明输出缓冲区保留回车(换行符)现象的存在
	//printf("%c",getchar());
	getchar();
	//1.设置一个循环 - 用以对多个字符串轮流进行检测 - 每一轮循环对应一次检测
	//2.设置一个内层循环 - 用以对单个字符串的每个字符进行检测 - 每一轮对应一个字符
	for (i = 0; i < n; i++)
	{	//1.p==1 2.t==1 3.xp*pxt==tx 4.pxt>0 5.P比T先出现
		p = 0;//表示P的个数
		t = 0;//表示T的个数
		x = 0;//表示P前面的A的个数
		Y = 0;//表示P、T之间的A的个数
		z = 0;//表示T后面的A的个数
		while ((c = getchar()) != '\n')
		{
			if (c == 'P')
			{
				p++;
				if ((p > 1))
				{
					result[i] = 0;
					break;
				}
			}
			else if (c == 'T')
			{
				t++;
				if ((t > 1) || (p == 0))
				{
					result[i] = 0;
					break;
				}
			}
			else if (c == 'A')
			{
				if (p == 0)
				{
					x++;
				}
				else if (t == 0)
				{
					Y++;
				}
				else
				{
					z++;
				}
			}
			else
			{
				result[i] = 0;
				break;
			}
		}
		if (result[i] == 0)
		{
			while ((getchar()) != '\n')
			{
				;
			}
		}
		if ((Y == 0)||(p!=1)||(t!=1))
		{
			result[i] = 0;
		}
		if (x * Y != z)
		{
			result[i] = 0;
		}
	}
	for (i = 0; i < n; i++)
	{
		if (result[i])
		{
			printf("YES");
		}
		else
		{
			printf("NO");
		}
		if (i != (n - 1))
		{
			printf("\n");
		}
	}
	return 0;
}
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值