蓝桥杯算法特训 | 数学知识的运用 |未完待续

本节课的主要内容:

数学知识的运用

    1)并非数学竞赛

    2)进制问题及其巧妙运用

    3)整数与整除问题

    4)欧几里得扩展定理

    5)有理数表示,大数问题

题1:地产大亨Q先生临终的遗愿是:拿出100万元给X社区的居民抽奖,以稍慰藉心中愧疚。麻烦的是,他有个很奇怪的要求:

1. 100万元必须被正好分成若干份(不能剩余)。
  每份必须是7的若干次方元。
  比如:1元, 7元,49元,343元,...
  
2. 相同金额的份数不能超过5份。

3. 在满足上述要求的情况下,分成的份数越多越好!

请你帮忙计算一下,最多可以分为多少份?

解法:暴力枚举、七的进制

#include
#include
using namespace std;
int count = 0;
int visit[10] = {0};        //7的10次方已经超过100万
int num;
//step代表7的几次方 
void dfs(int step,int count)
{
	if(visit[step] >5)
	{
		return;
	 } 
	if(count>1000000)
	{
		return;
	}else if(count==1000000)
	{
		num = 0;
		for(int i=0;i<10;i++)
		{
			num += visit[i];
			//计算份数 
		}
		cout<

上面用到的是深度优先搜索

伪代码:

void dfs(状态A)
{
	if(A不合法)
		return;
	if(A为目标状态)
		return;
	if(A不为目标状态)
		dfs(A+..);	//递归调用 
 } 

以下是利用进制的转换的解法

#include 
#include 
#include 
#include 
#include 
using namespace std;

void solve()
{
	char arr[1024] = {0};
	//将1000*1000以7进制的形式,转换成字符串存储到arr数组中
	//a[0]*7^n + a[1]*7^n-1 + .... a[n-1]*7^0
	//用到itoa函数
	_itoa(1000*1000,arr,7);
	int sum = 0;
	for(int i = 0;i

itoa函数:

它的功能是将一个10进制的数转化为n进制的值、其返回值为char型。(和上面的strtol效果相反)

例如:itoa(num, str, 2); num是一个int型的,是要转化的10进制数,str是转化结果,后面的值为目标进制。

#include  
#include  
int main()  
{  
    int num = 10;  
    char str[100];  
    itoa(num, str, 2);  
    printf("%s\n", str);  
    return 0;  
} 
题2:用天平称重时,我们希望用尽可能少的砝码组合称出尽可能多的重量。
如果只有5个砝码,重量分别是1,3,9,27,81
则它们可以组合称出1到121之间任意整数重量(砝码允许放在左右两个盘中)。

本题目要求编程实现:对用户给定的重量,给出砝码组合方案。
例如:
用户输入:
5
程序输出:
9-3-1
用户输入:
19
程序输出:
27-9+1
要求程序输出的组合总是大数在前小数在后。

可以假设用户的输入的数字符合范围1~121。

暴力解法(结尾的输出部分感觉有点问题)

#include
using namespace std;
int main()  
{  
    int can[5];  
    //每个砝码有三种状态,要么相加,要么相减,要么啥也不干  
    int a[3] = {0,1,-1};  
    int b[3] = {0,3,-3};  
    int c[3] = {0,9,-9};  
    int d[3] = {0,27,-27};  
    int e[3] = {0,81,-81};  
    int h,i,j,k,m,n;  
    cin>>n; 
    for (i = 0; i < 3; i++)  
        for (j = 0; j < 3; j++)  
            for (k = 0; k < 3; k++)  
                for (m = 0; m < 3; m++)  
                    for(h = 0; h < 3; h++)  
                    {  
                        if (a[i] + b[j] + c[k] + d[m] + e[h] == n)  
                        {  
                            can[4] = a[i];  
                            can[3] = b[j];  
                            can[2] = c[k];  
                            can[1] = d[m];  
                            can[0] = e[h];  
                        }  
                    }  
    for (i = 0; i < 5; i++)  
    {  
        if (i == 0)  
            cout< 0)  
            cout<<"+"<
进制解法
#include
#include
using namespace std;
bool cmp(int a,int b)
{
	return abs(a)>abs(b);
}
int main()
{
	int z,count =0;
	int n;
	int a[10] = {0};
	int b[10] = {1,3,9,27,81};
	int c[10] = {0};
	
	cin>>n;
	z = n;
	while(z>=3)
	{
		a[count++] = z % 3;
		//余数 
		z = z/3;
		//倍数 
	}
	if(z !=0 ){
		a[count++] = z;
	}
	
	int s=0;
	for(int i= 0;i < 10;i++)
	{
		if(a[i]!=0){
			if(a[i]==1)
			{
				c[s++] = b[i];
			}
			else{
				c[s++] = 0 - b[i];
				a[i+1]++;
			}
		}
		
	 } 
	 
	 sort(c,c+10,cmp);
	 for(int i=0;i <10;i++)
	 {
	 	if(i==0)
	 		cout<0){
	 		cout<<"+"<

题3:尼姆堆

有3堆硬币,分别是3,4,5
二人轮流取硬币。
每人每次只能从某一堆上取任意数量。
不能弃权。
取到最后一枚硬币的为赢家。

求先取硬币一方有无必胜的招法。

//模2的加法  数论  同余理论

有已证明理论,如果和为0,无论怎么拿,都会!=0  如果非0,总有办法。。。。0

三堆数目: 3   4    5 

二进制      11 100  101  模2加 = 010 

#include
#include
using namespace std;

void f(int *a,int len)
{
	int sum = 0;
	for(int i=0;i"<

题4:

如果两个数很大,怎样求最大公约数,最小公倍数?

如果是n个数呢?比如1000个数的最小公倍数

辗转相除法
欧几里得定理 gcd(A,B) = gcd(B,A%B)

算数基本定理:质因数分解的唯一性

#include
using namespace std;

int gcd(int a, int b)
{
	if (b == 0) 
		return a;
	return gcd(b, a%b);
}

int lcm(int a, int b)
{
	return a * b / gcd(a, b);
}

int main()
{
	cout<


题5:

从昏迷中醒来,小明发现自己被关在X星球的废矿车里。
矿车停在平直的废弃的轨道上。
他的面前是两个按钮,分别写着“F”和“B”。

小明突然记起来,这两个按钮可以控制矿车在轨道上前进和后退。
按F,会前进97米。按B会后退127米。
透过昏暗的灯光,小明看到自己前方1米远正好有个监控探头。
他必须设法使得矿车正好停在摄像头的下方,才有机会争取同伴的援助。
或许,通过多次操作F和B可以办到。

矿车上的动力已经不太足,黄色的警示灯在默默闪烁...
每次进行 F 或 B 操作都会消耗一定的能量。
小明飞快地计算,至少要多少次操作,才能把矿车准确地停在前方1米远的地方。

请填写为了达成目标,最少需要操作的次数。

#define  _CRT_SECURE_NO_WARNINGS
#include
#include 
#include
using namespace std;
/*
解不定方程
97x + 127y = 1

欧几里得定理 ---- 辗转相除法  gcd
扩展欧几里得定理
Ax + By = gcd(A,B)
理论基础: gcd(A,B) == gcd(B,A%B)

求出特解后,通解很好表示

Ax + By = gcd(A,B)
Ax + By = gcd(B,A%B)
B(A/B x + y) + (A%B)x = gcd(B,A%B)
对比:
A/B x + y = 新x
x = 新y
*/

// 返回最大公约数
// xy: 顺便解出的xy
int e_gcd(int A, int B, int* xy,int len)
{
	if (B == 0)
	{
		xy[0] = 1;
		xy[1] = 0;
		return A;
	}

	int ans = e_gcd(B, A%B, xy,len);
	int t = xy[0];
	xy[0] = xy[1];
	xy[1] = t - A / B * xy[0];
	return ans;
}

int main()
{
	int* xy =(int *) malloc(sizeof(int)*2);
	int a = e_gcd(97, 127, xy,2);
	cout<

你可能感兴趣的:(蓝桥杯算法特训)