有100张按顺序写着1-100数字的牌,一开始所有牌都是背面朝上。接下来,从第3张牌开始,隔2张牌翻牌(原本正面的变反面,反面的变正面)。然后又从第4张开始,隔三张牌翻牌。一直做下去,从第n张牌开始,每隔n-1张牌翻牌,直到没有可翻动的牌为止,求所有背面朝上的牌的数字?
思路:我们看到,从第n张牌开始往后,隔n-1张牌翻牌,是一直从左往右处理牌,所以只要用一个数组来存储这些牌,数组下标为牌的数字,下标对应的数组元素代表牌的正反面状态,然后按顺序处理对牌进行“翻转“就可以了,如果牌面朝上,对应下标元素就为1,否则牌面朝下,对应下标元素就为0。
#include <stdio.h>
int main (int aggc, char const* argv[])
{
int arr[101]={0}; /*0表示反面,1表示正面*/
int i, j;
/*初始化牌组*/
// for (i=1; i<=100; i++) {
// arr[i]=0;
// }
/*输出牌组初始值看看*/
printf("初始牌组:");
for (i=1; i<=100; i++) {
printf("%d ", arr[i]);
}
printf("\n");
/*开始翻牌*/
for (i=2; i<=100; i++) {
for (j=i; j<=100; j+=i) {
arr[j]=!arr[j];
}
}
/*输出最后牌组*/
printf("\n最后牌组:");
for (i=1; i<=100; i++) {
printf("%d ", arr[i]);
}
printf("\n");
printf("\n所有背面朝上的牌的数字:");
for (i=1; i<=100; i++) {
if (arr[i]==0) {
printf("%d\t", i);
}
}
return 0;
}
#include <stdio.h>
int main (int aggc, char const* argv[])
{
int arr[101]={0}; /*0表示反面,1表示正面*/
int i, j, number;
/*初始化牌组*/
// for (i=1; i<=100; i++) {
// arr[i]=0;
// }
/*输出牌组初始值看看*/
printf("初始牌组:");
for (i=1; i<=100; i++) {
printf("%d ", arr[i]);
}
printf("\n");
printf("\n请输入要反转到第n次牌:");
scanf("%d", &number);
/*开始翻牌*/
for (i=2; i<=number; i++) {
for (j=i; j<=100; j+=i) {
arr[j]=!arr[j];
}
}
/*输出最后牌组*/
printf("\n最后牌组:");
for (i=1; i<=100; i++) {
printf("%d ", arr[i]);
}
printf("\n");
printf("\n所有背面朝上的牌的数字:");
for (i=1; i<=100; i++) {
if (arr[i]==1) {
printf("%d\t", i);
}
}
return 0;
}
我们从上面结果可以看到,从第2开始翻到第100,也就是翻到所有牌不再变动后,结果是1、4、9、16、25、36、49、64、81、100。这些数是不是很有规律?它们分别是1²、2²、3²。。。。。9²,10²。都是平方数。
还有一个规律,我们的牌一开始全是背面朝上,如果牌进行了奇数次反转,最后是正面朝上的;如果牌进行了偶数次反转,最后是反面朝上的。我们题目问最后反面朝上的牌的数字,也就是说寻找反转了偶数次的牌有哪些。
那么怎么计算牌的最后反转次数是奇数还是偶数呢?我们知道某张牌经过反转后,反面朝上的话,那么就是经过偶数次反转,如果这个的翻牌间隔k这个牌数N的约数,那么这张牌数一定能经过k个间隔到达N并进行反转操作(表述的不好- -、)。所以会进行翻牌操作。
接着我们用逆推的思想看,4的约数有1、2、4三个,9的约数有1、3、9、三个,16的约数有1、2、4、8、16五个……也就是说,我们要找平方数且它的约数个数是奇数个的数(当然你也可以从2开始,寻找约数是偶数个的数)。
所以根据这个思路,我们可以把代码简化为:
#include <stdio.h>
int main (int aggc, char const* argv[])
{
int arr[101]={0}; /*0表示反面,1表示正面*/
int i, j;
/*初始化牌组*/
// for (i=1; i<=100; i++) {
// arr[i]=0;
// }
/*输出牌组初始值看看*/
printf("初始牌组:");
for (i=1; i<=100; i++) {
printf("%d ", arr[i]);
}
printf("\n\n所有背面朝上的牌的数字:");
for (i=1; i<=100; i++) {
arr[i]=0;
for (j=1; j<=100; j++) {
/*如果是约数,就进行翻牌操作*/
if (i%j==0) {
arr[i]=!arr[i];
}
}
if (arr[i]==1) {
printf("%d ", i);
}
}
}
完整代码在个人代码云: