C语言实践第二次习题集之旋转骰子
旋转骰子
题目
玛莎有n个骰子,每个骰子的6个面上都恰好有一个0到9之间的数字。
现在玛莎将利用这n个筛子来制作新数字。她把n个骰子摆成一排,然后从左到右查看骰子的上表面并读取,即可得到一个新数字。随后她不断的旋转每个骰子的面就可以得到不同的新数字。旋转骰子需要满足以下规则:
1、制作的数字不能包含前导零; 2、制作新数字时不需要使用所有的骰子; 3、使用骰子旋转,无法将数字9转换为数字6,反之亦然。
给定n个骰子,玛莎可以用它们构成从1到x的所有整数。玛莎想知道,对于给定的n个骰子,这个x的最大取值是多少呢?
输入格式:
第一行仅一个整数n,表示骰子的数量(1≤n≤3)。
接下来n行,每行包含6个整数a[i][j](0≤a[i][j]≤9),表示第i个骰子的第j个面上的数字。
输出格式:
输出一个整数,即最大数x,玛莎可以使用她的骰子构成数字从1到x。如果无法构成1,则输出0。
输入样例:
3
0 1 3 5 6 8
1 2 4 5 7 8
2 3 4 6 7 9
输出样例:
98
思路
这题思路其实挺简单的,因为1<=n<=3,n的取值不是很大,所以我写了几个特判,手法比较粗暴。另外,n取值较大的话解法还是挺值得思考的。
还有就是这题算是模拟类型的题目吧,有一些常用的技巧,比如设置数组来标记啊啥的。
完整代码
#include<stdio.h> void make_num1(int s);//第一类生成函数 void make_num2(int start,int end);//第二类生成函数 void make_num3(int s);//第三类生成函数 int num[3][6],vis[1005];//vis数组用于标记本次生成的数在之前是否已生成过了 int main() { int n,i,j; scanf("%d",&n); vis[0]=0;//把vis数组初始化 for(i=0;i<3;i++){ for(j=0;j<6;j++){ scanf("%d",&num[i][j]); } } //分层处理 for(i=0;i<n;i++) make_num1(i);//第一类生成函数针对单个骰子的情况 if(n>=2){//n大于等于2时,要开始考虑两个骰子一起组成数字的情况了 make_num2(0,1); /*这里注意还需考虑骰子的顺序可以颠倒,比如编号为0的骰子 和编号为1的骰子可以从0读取到1,也可从1读取到0*/ make_num2(1,0); } if(n==3){ make_num2(1,2);//编号为1和编号为2的骰子 make_num2(2,1);//记得颠倒 make_num2(0,2);//别忘了0号和2号骰子 make_num2(2,0); make_num3(0);//第三类生成函数 make_num3(-1);//同样也要颠倒,从2号到1号到0号 } for(i=1;vis[i]!=0;i++) ;//找出第一个未生成数的位置 if(i==1) printf("0"); else printf("%d",i-1); return 0; } void make_num1(int s) { int i; for(i=0;i<6;i++){ if(vis[num[s][i]]==0) vis[num[s][i]]=1;//赋值为1,表示已生成该数 } } void make_num2(int start,int end) { int i,j,store; for(i=0;i<6;i++){ for(j=0;j<6;j++){ store=num[start][i]*10+num[end][j]; if(vis[store]==0) vis[store]=1; } } } void make_num3(int s) { int i,j,k,store,s1=2,s2=1,s3=0;//s1,s2,s3在默认情况下设为从0读到1再读到2的顺序 if(s==0){//进行颠倒情形运算的预处理 s1=0; s2=1; s3=2; } for(i=0;i<6;i++){ for(j=0;j<6;j++){ for(k=0;k<6;k++){ store=num[s1][i]*100+num[s2][j]*10+num[s3][k]; if(vis[store]==0) vis[store]=1; } } } }