蓝桥杯之暴力破解、枚举

美国数学家维纳(N.Wiener)智力早熟,11岁就上了大学。
他曾在1935~1936年应邀来中国清华大学讲学。
一次,他参加某个重要会议,年轻的脸孔引人注目。
于是有人询问他的年龄,他回答说:
“我年龄的立方是个4位数。我年龄的4次方是个6位数。这10个数字正好包含了从0到9这10个数字,每个都恰好出现1次。”
请你推算一下,他当时到底有多年轻。


思路:
通过暴力破解的方法,我们可以找到年龄的大概范围,10^3=1000,30^4=8100
代码:


#include<stdio.h>
#include<math.h>

int main(){
	for(int i=10;i<=30;i++){
		printf("%d= %.0f %.0f\n",i,pow(i,3),pow(i,4));
	}
}

通过观察,我们发现18即为正确答案。
注意,pow(x,y)的返回值为double


------------------------------------------------


古罗马帝国开创了辉煌的人类文明,但他们的数字表示法的确有些繁琐,尤其在表示大数的时候,现在看起来简直不能忍受,所以在现代很少使用了。
之所以这样,不是因为发明表示法的人的智力的问题,而是因为一个宗教的原因,当时的宗教禁止在数字中出现0的概念!
罗马数字的表示主要依赖以下几个基本符号:


I --> 1
V --> 5
X --> 10
L --> 50
C --> 100
D --> 500
M --> 1000


这里,我们只介绍一下1000以内的数字的表示法。
单个符号重复多少次,就表示多少倍。最多重复3次。
比如:CCC表示300  XX表示20,但150并不用LLL表示,这个规则仅适用于I X C M。


如果相邻级别的大单位在右,小单位在左,表示大单位中扣除小单位。
比如:IX表示9  IV表示4  XL表示40 
49 = XLIX
    
更多的示例参见下表,你找到规律了吗?    
I = 1 
II = 2
III = 3
IV = 4
V = 5
VI = 6
VII = 7
VIII = 8
IX = 9 
X = 10
XI = 11
XII = 12
XIII = 13
XIV = 14
XV = 15
XVI = 16
XVII = 17
XVIII = 18
XIX = 19
XX = 20
XXI = 21
XXII = 22
XXIX = 29
XXX = 30
XXXIV = 34
XXXV = 35
XXXIX = 39
XL = 40
L = 50
LI = 51
LV = 55
LX = 60
LXV = 65
LXXX = 80
XC = 90
XCIII = 93
XCV = 95
XCVIII = 98
XCIX = 99
C = 100
CC = 200
CCC = 300
CD = 400
D = 500
DC = 600
DCC = 700
DCCC = 800
CM = 900
CMXCIX = 999


本题目的要求是:请编写程序,由用户输入若干个罗马数字串,程序输出对应的十进制表示。


输入格式是:第一行是整数n,表示接下来有n个罗马数字(n<100)。
以后每行一个罗马数字。罗马数字大小不超过999。
要求程序输出n行,就是罗马数字对应的十进制数据。


例如,用户输入:
3
LXXX
XCIII
DCCII


则程序应该输出:
80
93
702


思路:本题有一个很大的突破点,即如何表示右边比,仔细观察,你会发现赭红情况的数字只有那么几个,即:4、9、40、90、400、900,因此,不妨使用枚举的方法进行排除。我们先对每个字母表示原来的数字进行累加,最后减去多加的部分,就可以得到正确答案。


C语言定义字符串:char s[];
C语言求字串:strstr(str1,str2);返回str1中首次出现str2的位置。


代码:
#include<stdio.h>
#include<string.h>


int romeNum(char s[]);
int main(){
	int n;
	scanf("%d",&n);
	while(n--){
		char str[6];
		scanf("%s",str);
		printf("%d\n",romeNum(str));
	}
} 


int romeNum(char s[]){
	int sum;
	for(int i=0;i<strlen(s);i++){
		char c = s[i];
		if(c=='I') sum+=1;
		if(c=='V') sum+=5;
		if(c=='X') sum+=10;
		if(c=='L') sum+=50;
		if(c=='C') sum+=100;
		if(c=='D') sum+=500;
		if(c=='M') sum+=1000;
	}
	if(strstr(s,"IV")!=NULL) sum-=2;
	if(strstr(s,"IX")!=NULL) sum-=2;
	if(strstr(s,"XL")!=NULL) sum-=20;
	if(strstr(s,"XC")!=NULL) sum-=20;
	if(strstr(s,"CD")!=NULL) sum-=200;
	if(strstr(s,"CM")!=NULL) sum-=200;
	return sum;
}

------------------------------------------------


小明最近在教邻居家的小朋友小学奥数,而最近正好讲述到了三阶幻方这个部分。
三阶幻方指的是将1~9不重复的填入一个3*3的矩阵当中,使得每一行、每一列和每一条对角线的和都是相同的。
三阶幻方又被称作九宫格,在小学奥数里有一句非常有名的口诀:
“二四为肩,六八为足,左三右七,戴九履一,五居其中”,
通过这样的一句口诀就能够非常完美的构造出一个九宫格来。
4 9 2
3 5 7
8 1 6
有意思的是,所有的三阶幻方,都可以通过这样一个九宫格进行若干镜像和旋转操作之后得到。
现在小明准备将一个三阶幻方(不一定是上图中的那个)中的一些数抹掉,交给邻居家的小朋友来进行还原,并且希望她能够判断出究竟是不是只有一个解。

而你呢,也被小明交付了同样的任务,但是不同的是,你需要写一个程序~


输入格式:
输入仅包含单组测试数据。
每组测试数据为一个3*3的矩阵,其中为0的部分表示被小明抹去的部分。
对于100%的数据,满足给出的矩阵至少能还原出一组可行的三阶幻方。


输出格式:
如果仅能还原出一组可行的三阶幻方,则将其输出,否则输出“Too Many”(不包含引号)。


样例输入
0 7 2
0 5 0
0 3 0


样例输出
6 7 2
1 5 9
8 3 4


思路:
因为三阶幻方经过变换,最终只有8种结果,所以,我们采用枚举的方式,首先将8中可能性都写出来,然后将输入的数据与每一种可能进行对比。


代码:
#include<stdio.h>

int isTrue(int b[]);
int main(){
	int a[9];
	for(int i=0;i<9;i++){
		scanf("%d",&a[i]);
	}
	isTrue(a);
	return 0;
}


int isTrue(int b[]){
	int a[8][9]={
		{4,9,2,3,5,7,8,1,6},
		{8,3,4,1,5,9,6,7,2},
		{6,1,8,7,5,3,2,9,4},
		{2,9,4,7,5,3,1,8,6},
		{8,1,6,3,5,7,4,9,2},
		{6,7,2,1,5,9,8,3,4},
		{2,9,4,7,5,3,6,1,8},
		{1,8,6,7,5,3,2,9,4}
	};	
	
	printf("\n");
	
	for(int i=0;i<8;i++){
		int flag=1;
		for(int j=0;j<9;j++){
			if(b[j]==0) continue;
			if(a[i][j]!=b[j]) flag=0;
		}
		if(flag==1){
			printf("%d %d %d\n%d %d %d\n%d %d %d\n",a[i][0],a[i][1],a[i][2],a[i][3],a[i][4],a[i][5],a[i][6],a[i][7],a[i][8],a[i][9]);
			break;
		}		
	}
	
}


------------------------------------------------



魔方可以对它的6个面自由旋转。


我们来操作一个2阶魔方(如图1所示):
为了描述方便,我们为它建立了坐标系。


各个面的初始状态如下:
x轴正向:绿
x轴反向:蓝
y轴正向:红
y轴反向:橙
z轴正向:白
z轴反向:黄


假设我们规定,只能对该魔方进行3种操作。分别标记为:
x 表示在x轴正向做顺时针旋转
y 表示在y轴正向做顺时针旋转
z 表示在z轴正向做顺时针旋转


xyz 则表示顺序执行x,y,z 3个操作


题目的要求是:
用户从键盘输入一个串,表示操作序列。
程序输出:距离我们最近的那个小方块的3个面的颜色。
顺序是:x面,y面,z面。


例如:在初始状态,应该输出:
绿红白


初始状态下,如果用户输入:
x
则应该输出:
绿白橙


初始状态下,如果用户输入:
zyx
则应该输出:
红白绿


------------------------------------------------


【信用卡号的验证】


当你输入信用卡号码的时候,有没有担心输错了而造成损失呢?其实可以不必这么担心,因为并不是一个随便的信用卡号码都是合法的,它必须通过Luhn算法来验证通过。
该校验的过程:
1、从卡号最后一位数字开始,逆向将奇数位(1、3、5等等)相加。
2、从卡号最后一位数字开始,逆向将偶数位数字,先乘以2(如果乘积为两位数,则将其减去9),再求和。
3、将奇数位总和加上偶数位总和,结果应该可以被10整除。
例如,卡号是:5432123456788881


则,奇数位和=35
偶数位乘以2(有些要减去9)的结果:1 6 2 6 1 5 7 7,求和=35。
最后35+35=70 可以被10整除,认定校验通过。


请编写一个程序,从键盘输入卡号,然后判断是否校验通过。通过显示:“成功”,否则显示“失败”。
比如,用户输入:356827027232780
程序输出:成功


【参考测试用例】
356406010024817     成功
358973017867744     成功
356827027232781     失败
306406010024817     失败
358973017867754     失败


思路:
这道题很简单,直接一次取模相加就好,有一个坑,就是不能使用int型来保存输入的数据,会越界。


代码:
#include<stdio.h>

void isTrue(long long n);
int main(){
	long long n;
	scanf("%lld",&n);
	isTrue(n);
	return 0;
} 
void isTrue(long long n){
	int flag=1,sum=0;
	while(n){
		if(flag){
			sum+=n%10;
			n=n/10;
			flag=0;
			
		}else{
			int t=(n%10)*2;
			if(t>9) t=t-9;
			sum+=t;
			n=n/10;
			flag=1;
		}
	}
	
	if(sum%10==0){
		printf("成功");
	}else{
		printf("失败");
	}
}

阅读更多
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页