C语言趣味编程


前言

在初学编程的时候,兴趣能够增加坚持下去的动力。为了增添学习趣味,可以试着去做一些有意思的题目。让编程显得不在那么枯燥。以下分享两道还算比较有趣的题目。


一、柯南找凶手

题目描述

日本某地发生了一件谋杀案,警察通过排查确定杀人凶手必为4个嫌疑犯的一个。
以下为4个嫌疑犯的供词:
A说:不是我。
B说:是C。
C说:是D。
D说:C在胡说
已知3个人说了真话,1个人说的是假话。
现在请根据这些信息,写一个程序来确定到底谁是凶手。

这道题目让你化身柯南去查找真凶,题目还是比较有意思的。那么怎么用程序实现找凶手呢?首先,对于我们来说,推理过程就是,先假设a是对的,然后结合条件,进行比对判断,判断是否矛盾,依次比较,直到假设推理符合实际条件。所以基于这种想法,只需要把每种情形枚举出来,进行判断即可。
暴力枚举代码示例

#include<stdio.h>
int main()
{
	char killer = 'A';
	for ( killer;killer <= 'D'; killer++)
	{
		if ((killer != 'A') + 
		(killer == 'C') + 
		(killer == 'D') + 
		(killer != 'D') == 3)
		{
			printf("%c", killer);
		}
	}
}

用+号连接进行逻辑判断,满足条件即可。

二、定夺名次

题目描述

5位运动员参加了10米台跳水比赛,有人让他们预测比赛结果:
A选手说:B第二,我第三;
B选手说:我第二,E第四;
C选手说:我第一,D第二;
D选手说:C最后,我第三;
E选手说:我第四,A第一;
比赛结束后,每位选手都说对了一半,请编程确定比赛的名次。

还是上述思想处理问题,就是假设推理挨个试错,在编程中就是暴力枚举,这题关键之处就是逻辑判断怎么表示,因为每个人说话都是对了一半。不知道是前面对,还是后面对,所以对每个人的话用加号连接同时判断是否等于1,这就表明了对了一半,同时对于每个人说的话用并且(&&)连接,如果用或者(||)来连接不能保证每个人说的话都是真,如果不想用&&来连接,只用将每个人的语句判断之和相加,再判断之和是否为5,因为每个人两句话,只对了一半。
代码如下(示例):

#include<stdio.h>
int main()
{
	int a = 0;
	int b = 0;
	int c = 0;
	int d = 0;
	int e = 0;
	for (a = 1; a < 6; a++)
	{
		for (b = 1; b < 6; b++)
		{
			for (c = 1; c < 6; c++)
			{
				for (d = 1; d < 6; d++)
				{
					for (e = 1; e < 6; e++)
					{
						if (((a == 3) + (b == 3) == 1) &&
							((b == 2) + (e == 4) == 1) &&
							((c == 1) + (d == 2) == 1) &&
							((c == 5) + (d == 3) == 1) &&
							((e == 4) + (a == 1) == 1))
						{
							if ((a * b * c * d * e == 120) && 
							(a + b + c + d + e == 15))
			printf("a=%d b=%d c=%d d=%d e=%d\n", a, b, c, d, e);
						}
					}
				}
			}
		}
	}
	return 0;
}

但是这题还是有点小坑,因为你的逻辑判断之后没有去重,可能会有多个错误结果满足逻辑判断条件。比如说 a=4 ;b=5;c=4,e=2;d=1;正确的名次和错误的名次混合着输出,这个时候需要进行去重判断,来确保输出的每个名次都是唯一的。因为a b c d e 是取值1到5,所以五个数的和为15,五个数的积为120。这样才能确保数据名次的唯一性。

三.密码判断

小明同学最近开发了一个网站,在用户注册账户的时候,需要设置账户的密码,为了加强账户的安全性,小明对密码强度有一定要求:

  1. 密码只能由大写字母,小写字母,数字构成;
  2. 密码不能以数字开头;
  3. 密码中至少出现大写字母,小写字母和数字这三种字符类型中的两种;
  4. 密码长度至少为8现在小明受到了n个密码,他想请你写程序判断这些密码中哪些是合适的,哪些不合法的。
    注(输入一个数n,接下来有n(n≤100)行,每行一个字符串,表示一个密码,输入保证字符串中只出现大写字母,小写字母和数字,字符串长度不超过100。
    输入n行,如果密码合法,输出YES,不合法输出NO)

首先先简单分析一下题目,对于数据的输入是多行的,因此整个的数据的输入的判断是采用循环的方式,这时候就得考虑一下数据的判断以何种方式结束,因为输入的数据不知道是否合法,对于不合法的数据判断出结果后,就应该马上接着处理下一组数据。采用的是循环处理数据,因此在想跳出循环的话,常见的不外乎就是break和continue 。因为对输入数据处理的交替进行的,如果用break就会跳出循环,在数据还未处理完的情况下不会接着判断了。所以用continue来对非法数据的处理比较合适,一旦不满足以上任何一个要求就停止后面的判断,直接输出即可。

大体的思路有了,剩下的就是具体细节的实现。
首先输入的密码肯定是字符串类型的。
第一步判断字符串的长度是否大于等于8,如果不满足,就输出 NO,并且 continue.解决了要求4
第二步判断字符串的首字符是不是数字,,如果是就输出NO,并且 continue 解决了要求2
第三步判断字符串种类,针对 大小写字母 数字 其他字符 各设置4个计数器,并初始化为0,如果出现了
对应的字符,计数器就加一,同时在对计数器进行相应的判断即可。

代码实现

#include <stdio.h>
int main()
{
	int n = 0;
	int upper = 0;//大写字母计数器
	int lower = 0;//小写字母计数器
	int digit = 0;//数字计数器
	int other = 0;//其他字符计数器
	scanf("%d", &n);
	char password[101] = { 0 };
		
		while(scanf("%s", password)!=EOF)
        {if (strlen(password) < 8) 
		{//密码长度小于8
			printf("NO\n");
			continue;
		}
		if (password[0] >= '0' && password[0] <= '9')
		{//密码以数字开头
			printf("NO\n");
			continue;
		}
		char* ptr = password;
		while (*ptr != '\0')
		{ //统计各种字符个数
			if (*ptr >= 'a' && *ptr <= 'z')
			{
				lower++;
			}
			else if (*ptr >= 'A' && *ptr <= 'Z')
			{
				upper++;
			}
			else if (*ptr >= '0' && *ptr <= '9')
			{
				digit++;
			}
			else
			{
				other++;
			}
			ptr++; 
		}
		if (other > 0)
		{ // 有其他字符(注意:密码只能由数字和字母组成)
			printf("NO\n");
			continue;
		} //大写,小写,数字,必须具有两种以上,而比较运算真则1,假则0
		if ((upper > 0) + (lower > 0) + (digit > 0) >= 2)
		{ // 密码只有一种字符
			printf("YES\n");
			continue;
		} 
        printf("NO\n");
	}
	return 0;
}

总结

1.对于这种逻辑判断的题,如果没有特别好的方法,那就先直接用暴力枚举,直接挨个比较判断是否符合题目要求。
2.对于内部的逻辑判断要清楚用什么连接之间的逻辑关系。对于&&和||不清楚用哪个,可以先带入试着判断是否正确。
3.因为有些问题,仅仅进行逻辑判断还不够,为了确保答案的正确性,有时候还要去重判断。
4.对于处理题目要求多的问题,可以先将简单的要求处理完,在接着处理稍微复杂的要求,逐渐减少要求的规模,对于不同的要求但处理方式相同的问题,可以试着合并处理,将其归结为一个问题。
5.以上内容如有问题,欢迎指正!谢谢!

  • 1
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值