29 环
29 环
作者:
问题描述 :
明明喜欢玩游戏,而明明的爸爸也乐意陪明明玩各种各样的小游戏。但是在游戏中,明明的爸爸又十分注意培养明明的智力,他希望通过游戏,不仅能让明明得到快乐,而且又能让明明学到一些知识,锻炼他的思维能力,为将来的发展打下基础。
一天,明明的爸爸和明明做起了一个叫“环”的游戏。游戏的内容很简单但却很有趣,就是有1到9九个整数,他们以任意的顺序排列成一个圆环,然后要在这个圆环中剪一刀,再分别按顺时针和逆时针次序排列成两个九位数。现在的要求是,得到的这两个九位数差的绝对值能被396整除,问一共有几种剪环的方法。 例如九个数的排列为:1、2、3、4、5、6、7、8、9,在1和9之间剪一刀(注意:因为是一个环,所以1和9是相邻的。),顺时针形成的数为:123456789,逆时针形成的数为:987654321,这两个数的差的绝对值为:864197532,这个数能被396整除,因此这是一种符合规则的剪法,更奇妙的是,这也是这种排序方式的唯一剪法。
明明显然对这个游戏非常感兴趣,高兴地做起来。但是玩了几次后,明明发现这个游戏又并不是那么容易了,因为对于这九个数来说,虽然一共只有九种剪法,但是每种方法都要试,且还要做加法再做除法,他觉得非常的麻烦,玩着玩着就失去了兴趣。明明的爸爸发现了这个问题,于是就找到了你,他请你来帮明明一把,写一个程序,计算出某个排序中符合条件的剪法共有几种,这样的话可以大大鼓励明明玩游戏的兴致。
明明爸爸的问题可以归结为:将1至9这九个数字,以任意顺序排成一个环,请在某两个数字之间剪开,分别按顺时针和逆时针次序排列成两个九位数,要求剪开后所得到的这两个九位数的差能被396整除,问共有几种剪法?
输入说明 :
你写的程序要求从标准输入设备中读入测试数据作为你所写程序的输入数据。标准输入设备中有多组测试数据,输入的第一行有一个整数n,表示一共有多少组测试数据,接下来有n行,为n个测试数据,每组测试数据有9个数字,表示一种环的排列顺序,每个数字之间用一个空格隔开。每组测试数据与其后一组测试数据之间没有任何空行,第一组测试数据前面以及最后一组测试数据后面也都没有任何空行。
输出说明 :
对于每一组测试数据,你写的程序要求计算出一组相应的运算结果,并将这一组运算结果作为你所写程序的输出数据依次写入到标准输出设备中。每组运算结果为一个整数,即有多少种符合条件的剪法。每组运算结果的行首和行尾都没有任何空格,每组运算结果与其后一组运算结果之间没有任何空行,第一组运算结果前面以及最后一组运算结果后面也都没有任何空行。 注:通常,显示屏为标准输出设备。
输入范例 :
2
1 2 3 4 5 6 7 8 9
9 8 7 6 5 4 3 2 1
输出范例 :
1
1
解题思路:这道题目我有两种思路。
思路一:严格根据数学规律解决问题。题目中限定是9位数,假定现在的数字是123456789。
那么我们要产生顺时针数和逆时针数。
顺时针数:很简单
1 while(9--){
2 num = num * 10+rec[j];
3 j = (j+1)%9;
4 }
逆时针数怎么解决顺序问题呢?很容易想到
1 while(k--){
2 num = num * 10+rec[j];
3 j = (j-1)%9;
4 }
但是以上红色语句会导致j变成负数,为了使j在数组下标范围内,我们可以利用周期性,手动加上一个周期(取模不影响结果)即可,如下:
1 k = 9;
2 while(k--){
3 antinum = antinum*10+rec[j];
4 j = (j-1+9)%9;
5 }
完整代码如下:
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <math.h>
4 #include <string.h>
5 #include <ctype.h>
6
7
8 #define MAXNUM 9
9
10
11 int rec[MAXNUM] = {0};
12
13
14 int main(){
15
16 int n,i,j,temp,x,count;
17
18 int num,antinum;
19 int k = 9;
20 scanf("%d",&n);
21 while(n--){
22 count = 0;
23 for(i=0;i<9;i++){
24 scanf("%d",rec+i);
25 }
26
27 num = antinum=0;count=0;
28 for(i=0;i<9;i++){
29 k = 9;//k的作用是加和计算的计数器,9位数
30 //计算num
31 num = antinum=0;
32 j=i;
33 while(k--){
34 num = num * 10+rec[j];
35 j = (j+1)%9;
36 }
37 j=(8+i)%9;
38 k = 9;
39 while(k--){
40 antinum = antinum*10+rec[j];
41 j = (j+8)%9;
42 }
43 if(abs(num-antinum)%396==0){
44 count++;
45 }
46 }
47
48 printf("%d\n",count);
49
50 }
51 return 0;
52 }
思路二:代码在本机上的测试案例是正确的,自己手推思路也是正确的,但是提交OJ后显示TLE(超时)。可能是自己调用了一些耗费时间的库函数导致的。
不过思路值得借鉴。以后继续研究,欢迎大佬指正
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <math.h>
4 #include <string.h>
5 #include <ctype.h>
6
7
8 #define MAXNUM 9
9
10
11 int rec[MAXNUM] = {0};
12 int a[MAXNUM] = {0};//顺时针产生数字
13 int b[MAXNUM] = {0};//逆时针产生数字
14
15 void dealNum(char str[],int num[]);
16
17 int main(){
18
19 int n,i,j,temp,x,count;
20 char str[9];
21 scanf("%d",&n);
22 while(n--){
23 count = 0;
24 for(i=0;i<9;i++){
25 scanf("%d",&temp);
26 str[i] = temp + '0';
27 }
28 str[9] = '\0';
29
30 //拼接字符串,填充顺时针数字
31 dealNum(str,a);
32
33 char ch;
34 for(i=0;i<4;i++){
35 ch = str[i];
36 str[i] = str[8-i];
37 str[8-i] = ch;
38 }
39 //再一次
40 //拼接字符串,填充逆时针数字
41 dealNum(str,b);
42 int y;
43 //需要特殊处理下,才能对应上序号
44 for(i=1;i<=4;i++){
45 y = b[i];
46 b[i] = b[9-i];
47 b[9-i] = y;
48 }
49
50 //开始判断
51 for(i=0;i<9;i++){
52
53 x = abs(a[i]-b[i]);
54 if(x%396==0){
55 count++;
56 }
57 }
58 printf("%d\n",count);
59
60 }
61 return 0;
62 }
63
64 void dealNum(char str[],int num[]){
65
66 int i;
67 char str1[9],str2[9];
68 for(i=0;i<9;i++){
69 strcpy(str1,str+i);
70 strncpy(str2,str,i);
71 str2[i] = '\0';
72 strcat(str1,str2);
73 num[i] = atoi(str1);
74
75 }
76
77 }