1.煤球数目
有一堆煤球,堆成三角棱锥形。具体:
第一层放1个,
第二层3个(排列成三角形),
第三层6个(排列成三角形),
第四层10个(排列成三角形),
…
如果一共有100层,共有多少个煤球?
请填表示煤球总数目的数字。
注意:你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。
【思路】
找规律,f(n) = f(n - 1) + n
代码:
/*
推导发现,第一层是+ 2得到第二层,第二层加3得到第三层
所以第100层 = 99层的 + 100
结果:171700
*/
#include<iostream>
using namespace std;
const int maxn = 105;
int dp[maxn];
int DP()
{
dp[1] = 1;
for(int i = 2;i <= 100;i++)
{
dp[i] = dp[i - 1] + i;
}
int sum =0 ;
for(int i = 1;i <= 100;i++)
{
sum += dp[i];
}
//print dp
cout << "dp : ";
for(int i = 1;i <= 100;i++)
{
cout << dp[i] << " ";
}
cout << endl;
return sum;
}
int main()
{
cout << DP() << endl;
return 0;
}
2.生日蜡烛
某君从某年开始每年都举办一次生日party,并且每次都要吹熄与年龄相同根数的蜡烛。
现在算起来,他一共吹熄了236根蜡烛。
请问,他从多少岁开始过生日party的?
请填写他开始过生日party的年龄数。
注意:你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。
【思路】
直接暴力枚举他开始过生日的年龄
代码:
#include<iostream>
using namespace std;
int main()
{
int sum = 0;
bool flag = true;
for(int i = 1;i <= 100;i++)
{
sum = i;
flag = true;
for(int j = i + 1;j <= 200 && flag;j++)
{
sum += j;
if(sum > 236)
flag = false;
if(sum == 236)
{
cout << i << endl;
break;
}
}
}
/*
测试
sum = 26;
cout << sum << endl;
for(int i = 27;i <= 200;i++)
{
sum += i;
cout << i << endl;
if(sum == 236)
{
break;
}
}
*/
return 0;
}
答案:26
3.凑算式
B DEF
A + — -+ ------- = 10
C GHI
(如果显示有问题,可以参见【图1.jpg】)
这个算式中AI代表19的数字,不同的字母代表不同的数字。
比如:
6+8/3+952/714 就是一种解法,
5+3/1+972/486 是另一种解法。
这个算式一共有多少种解法?
注意:你提交应该是个整数,不要填写任何多余的内容或说明性文字。
【思路】:
我也用的暴力枚举,直接循环搜。在蓝桥杯中暴力是很常用的方法。那么这里注意一下选一个数就要做一个标记,跟回溯一样,因为不能同一个数选多次。然后再就是DEF它是等于D * 100 + E * 10 + F,记得我刚开始算的时候差点理解成D * E * F。。。
还有一点注意下,这里的除,都必须除尽,跟计算机中取整不同,不然会算出很多结果。
代码:(纯暴力,有点多。。。)
#include<iostream>
using namespace std;
const int maxn = 20;
int tag[maxn];
int ans = 0;
int main()
{
for(int a = 1;a <= 9;a++)
{
tag[a] = 1;
for(int b = 1;b <= 9;b++)
{
if(tag[b] != 1)
{
tag[b] = 1;
for(int c = 1;c <= 9;c++)
{
if(tag[c] != 1)
{
tag[c] = 1;
for(int d = 1;d <= 9;d++)
{
if(tag[d] != 1)
{
tag[d] = 1;
for(int e = 1;e <= 9;e++)
{
if(tag[e] != 1)
{
tag[e] = 1;
for(int f = 1;f <= 9;f++)
{
if(tag[f] != 1)
{
tag[f] = 1;
for(int g = 1;g <= 9;g++)
{
if(tag[g] != 1)
{
tag[g] = 1;
for(int h = 1;h <= 9;h++)
{
if(tag[h] != 1)
{
tag[h] = 1;
for(int i = 1;i <= 9;i++)
{
if(tag[i] != 1)
{
tag[i] = 1;
int x = g * 100 + h * 10 + i;
int y = d * 100 + e * 10 + f;
int r = b * x + c * y;
int z = c * x;
if(r % z == 0)
{
if(a + (r / z) == 10)
{
ans++;
cout<<a<<","<<b<<","<<c<<","<<d<<","<<e<<","<<f<<","<<g<<","<<h<<","<<i<<endl;
}
}
tag[i] = 0;
}
}
tag[h] = 0;
}
}
tag[g] = 0;
}
}
tag[f] = 0;
}
}
tag[e] = 0;
}
}
tag[d] = 0;
}
}
tag[c] = 0;
}
}
tag[b] = 0;
}
}
tag[a] = 0;
}
cout << ans << endl;
return 0;
}
算出来结果29.
4.快速排序
排序在各种场合经常被用到。
快速排序是十分常用的高效率的算法。
其思想是:先选一个“标尺”,
用它把整个队列过一遍筛子,
以保证:其左边的元素都不大于它,其右边的元素都不小于它。
这样,排序问题就被分割为两个子区间。
再分别对子区间排序就可以了。
下面的代码是一种实现,请分析并填写划线部分缺少的代码。
#include <stdio.h>
void swap(int a[], int i, int j)
{
int t = a[i];
a[i] = a[j];
a[j] = t;
}
int partition(int a[], int p, int r)
{
int i = p;
int j = r + 1;
int x = a[p];
while(1){
while(i<r && a[++i]<x);
while(a[--j]>x);
if(i>=j) break;
swap(a,i,j);
}
______________________;
return j;
}
void quicksort(int a[], int p, int r)
{
if(p<r){
int q = partition(a,p,r);
quicksort(a,p,q-1);
quicksort(a,q+1,r);
}
}
int main()
{
int i;
int a[] = {5,13,6,24,2,8,19,27,6,12,1,17};
int N = 12;
quicksort(a, 0, N-1);
for(i=0; i<N; i++) printf("%d ", a[i]);
printf("\n");
return 0;
}
注意:只填写缺少的内容,不要书写任何题面已有代码或说明性文字。
【思路】
要你程序填空,这也是我很烦的类型,如果遇到简单的还好,看一看,试一试就可以出来。如果程序本身写得就很复杂,然后又让你根据他的思路来填,那就很烦了!
这题其实还算好填的,要理解题意。你发现partition函数就是找到了一个标尺,以保证其左边的元素都不大于它,其右边的元素都不小于它,然后partition函数中的那个下标p,实际上就像快排中的那个参照点,所以也很好想了,就是swap(a, p, j);
5.抽签
X星球要派出一个5人组成的观察团前往W星。
其中:
A国最多可以派出4人。
B国最多可以派出2人。
C国最多可以派出2人。
…
那么最终派往W星的观察团会有多少种国别的不同组合呢?
下面的程序解决了这个问题。
数组a[] 中既是每个国家可以派出的最多的名额。
程序执行结果为:
DEFFF
CEFFF
CDFFF
CDEFF
CCFFF
CCEFF
CCDFF
CCDEF
BEFFF
BDFFF
BDEFF
BCFFF
BCEFF
BCDFF
BCDEF
…
(以下省略,总共101行)
#include <stdio.h>
#define N 6
#define M 5
#define BUF 1024
void f(int a[], int k, int m, char b[])
{
int i,j;
if(k==N){
b[M] = 0;
if(m==0) printf("%s\n",b);
return;
}
for(i=0; i<=a[k]; i++){
for(j=0; j<i; j++) b[M-m+j] = k+'A';
______________________; //填空位置
}
}
int main()
{
int a[N] = {4,2,2,1,1,3};
char b[BUF];
f(a,0,M,b);
return 0;
}
仔细阅读代码,填写划线部分缺少的内容。
注意:不要填写任何已有内容或说明性文字。
也是程序填空,但我觉得这道题比前一道简单点。如果能很好的理解全排列、递归,那这一题其实很好填
f(a, k + 1, m - j, b);
6.方格填数
如下的10个格子
(如果显示有问题,也可以参看【图1.jpg】)
填入0~9的数字。要求:连续的两个数字不能相邻。
(左右、上下、对角都算相邻)
一共有多少种可能的填数方案?
请填写表示方案数目的整数。
注意:你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。
【思路】
这是结果填空题。这题一看就是dfs尝试嘛,我直接用的深搜,这个方格实际上用一个一维数组来存就够了。
代码:
/*
穷举
3404
k == 6写掉一个判断,大意了。。。
fabs(a[1] - i) != 1
正确答案:1580
*/
#include<iostream>
#include<cmath>
using namespace std;
const int maxn = 20;
int a[maxn];
int tag[maxn];
int ans = 0;
void dfs(int k) //k表示格子的序号
{
if(k == 11)
{
ans++;
cout << "************" << endl;
for(int i = 1;i <= 10;i++)
{
cout << a[i] << " ";
}
cout << endl;
return ;
}
for(int i = 0;i <= 9;i++)
{
if(k == 1)
{
tag[i] = 1;
a[k] = i;
dfs(k + 1);
tag[i] = 0;
}
else if(k == 2)
{
if(fabs(a[1] - i) != 1 && tag[i] != 1)
{
tag[i] = 1;
a[k] = i;
dfs(k + 1);
tag[i] = 0;
}
}
else if(k == 3)
{
if(fabs(a[2] - i) != 1 && tag[i] != 1)
{
tag[i] = 1;
a[k] = i;
dfs(k + 1);
tag[i] = 0;
}
}
else if(k == 4)
{
if(fabs(a[1] - i) != 1 && tag[i] != 1)
{
tag[i] = 1;
a[k] = i;
dfs(k + 1);
tag[i] = 0;
}
}
else if(k == 5)
{
if(fabs(a[1] - i) != 1 && fabs(a[4] - i) != 1 && fabs(a[2] - i) != 1
&& tag[i] != 1)
{
tag[i] = 1;
a[k] = i;
dfs(k + 1);
tag[i] = 0;
}
}
else if(k == 6)
{
if(fabs(a[2] - i) != 1 && fabs(i - a[5]) != 1 && fabs(a[3] - i) != 1
&& tag[i] != 1 && fabs(a[1] - i) != 1)
{
tag[i] = 1;
a[k] = i;
dfs(k + 1);
tag[i] = 0;
}
}
else if(k == 7)
{
if(fabs(a[2] - i) != 1 && fabs(a[6] - i) != 1 && fabs(a[3] - i) != 1
&& tag[i] != 1)
{
tag[i] = 1;
a[k] = i;
dfs(k + 1);
tag[i] = 0;
}
}
else if(k == 8)
{
if(fabs(a[4] - i) != 1 && fabs(i - a[5]) != 1 && tag[i] != 1)
{
tag[i] = 1;
a[k] = i;
dfs(k + 1);
tag[i] = 0;
}
}
else if(k == 9)
{
if(fabs(a[4] - i) != 1 && fabs(i - a[5]) != 1 && fabs(i - a[6]) != 1
&& fabs(i - a[8]) != 1 && tag[i] != 1)
{
tag[i] = 1;
a[k] = i;
dfs(k + 1);
tag[i] = 0;
}
}
else if(k == 10)
{
if(fabs(a[5] - i) != 1 && fabs(i - a[6]) != 1 && fabs(i - a[9]) != 1
&& fabs(i - a[7]) != 1 && tag[i] != 1)
{
tag[i] = 1;
a[k] = i;
dfs(k + 1);
tag[i] = 0;
}
}
}
}
int main()
{
dfs(1);
cout << ans << endl;
return 0;
}
很遗憾的是,第一次做的时候k == 6的情况写掉一个条件,导致最后算出来3404.
就是第六个格子应该和第一个格子也有一些限制关系,但我看漏了。正确答案:1580
7.剪邮票
如【图1.jpg】, 有12张连在一起的12生肖的邮票。
现在你要从中剪下5张来,要求必须是连着的。
(仅仅连接一个角不算相连)
比如,【图2.jpg】,【图3.jpg】中,粉红色所示部分就是合格的剪取。
请你计算,一共有多少种不同的剪取方法。
请填写表示方案数目的整数。
注意:你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。
【思路】
这题我刚开始做的时候,也是没有思路,最后没有做出来,因为传统的深搜是不行的,对于图三这种情况,深搜解决不了。
查找思路之后,发现其实很简单啊。。就是一个深搜+一个广搜。我们相当于先对格子的序号进行一个组合,这就需要一个dfs。然后我们再对每一个组合进行bfs,看看它们是不是连在一起的!
蓝桥杯很喜欢考dfs+bfs的组合题目!
虽然思路清楚了,但写代码的时候也是写了半天,因为粗心大意,很多地方写错,导致程序运行结果错误,调试了半天才成功
#include<iostream>
#include<queue>
using namespace std;
int ans = 0;
int x[6]; //装选好的邮票序号
struct Node{
int x;
int y;
int num;
Node(int x, int y, int num)
{
this->x = x;
this->y = y;
this->num = num;
}
};
int m[3][4] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
int vis[3][4];
int tag[20];
bool jianzhi(int k, int i)
{
if(tag[i] == 1)
return false;
for(int j = 0;j < k;j++)
{
if(x[j] > i) //保证递增顺序
return false;
}
return true;
}
bool panduan(int x1, int y, int n)
{
bool ok = false;
if(x1 < 0 || y < 0 || x1 > 2 || y > 3) //这里写错。。。y >2了
return false;
if(vis[x1][y] == 1)
return false;
for(int i = 1;i <= 5;i++)
{
if(x[i] == n)
{
ok = true;
break;
}
}
return ok;
}
void Clear()
{
for(int i = 0;i < 3;i++)
{
for(int j = 0;j < 4;j++)
{
vis[i][j] = 0;
}
}
}
bool bfs(int n)
{
queue<Node> q;
int x = (n - 1) / 4;
int y = (n - 1) % 4;
q.push(Node(x, y, n));
vis[x][y] = 1;
int num = 1; //初始num应该为1,之前错写成0,调错找了半天。。。
while(!q.empty())
{
Node f = q.front();
if(panduan(f.x + 1, f.y, m[f.x + 1][f.y]))
{
q.push(Node(f.x + 1, f.y, m[f.x + 1][f.y]));
vis[f.x + 1][f.y] = 1;
num++;
}
if(panduan(f.x, f.y + 1, m[f.x][f.y + 1]))
{
q.push(Node(f.x, f.y + 1, m[f.x][f.y + 1]));
vis[f.x][f.y + 1] = 1;
num++;
}
if(panduan(f.x - 1, f.y, m[f.x - 1][f.y]))
{
q.push(Node(f.x - 1, f.y, m[f.x - 1][f.y]));
vis[f.x - 1][f.y] = 1;
num++;
}
if(panduan(f.x, f.y - 1, m[f.x][f.y - 1]))
{
q.push(Node(f.x , f.y - 1, m[f.x][f.y - 1]));
vis[f.x][f.y - 1] = 1;
num++;
}
q.pop();
}
Clear();
if(num == 5)
return true;
else
return false;
}
void dfs(int k)
{
if(k == 6) //到达边界
{
if(bfs(x[1])) //用bfs判断,如果这五个邮票是相连的,那么总结果就 + 1
{
ans++;
for(int i = 1;i <= 5;i++)
{
cout << x[i] << " ";
}
cout << endl;
}
return ;
}
//每次枚举不同的邮票序号
for(int i = 1;i <= 12;i++) //这里枚举要递增,确保结果不重复
{
if(jianzhi(k, i)) //如果这个邮票没有被用过
{
tag[i] = 1;
x[k] = i;
dfs(k + 1);
tag[i] = 0;
}
}
}
int main()
{
dfs(1);
cout << ans << endl;
return 0;
}
关键是思路啊。。。
8.四平方和
四平方和定理,又称为拉格朗日定理:
每个正整数都可以表示为至多4个正整数的平方和。
如果把0包括进去,就正好可以表示为4个数的平方和。
比如:
5 = 0^2 + 0^2 + 1^2 + 2^2
7 = 1^2 + 1^2 + 1^2 + 2^2
(^符号表示乘方的意思)
对于一个给定的正整数,可能存在多种平方和的表示法。
要求你对4个数排序:
0 <= a <= b <= c <= d
并对所有的可能表示法按 a,b,c,d 为联合主键升序排列,最后输出第一个表示法
程序输入为一个正整数N (N<5000000)
要求输出4个非负整数,按从小到大排序,中间用空格分开
例如,输入:
5
则程序应该输出:
0 0 1 2
再例如,输入:
12
则程序应该输出:
0 2 2 2
再例如,输入:
773535
则程序应该输出:
1 1 267 838
资源约定:
峰值内存消耗 < 256M
CPU消耗 < 3000ms
请严格按要求输出,不要画蛇添足地打印类似:“请您输入…” 的多余内容。
所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。
注意: main函数需要返回0
注意: 只使用ANSI C/ANSI C++ 标准,不要调用依赖于编译环境或操作系统的特殊函数。
注意: 所有依赖的函数必须明确地在源文件中 #include , 不能通过工程设置而省略常用头文件。
提交时,注意选择所期望的编译器类型。
【思路】
直接dfs枚举,我个人认为比上一题简单
代码:
/*
暂时只会暴力
773535
1 1 267 838
3535结尾的会很慢
*/
#include<iostream>
#include<algorithm>
using namespace std;
bool flag = false;
int x[5];
void dfs(int k, int val) //val表示现在的值
{
if(val == 0 || k == 5)
{
if(val == 0)
{
for(int i = 1;i <= 4;i++)
{
cout << x[i] << " ";
}
cout << endl;
flag = true;
}
return ;
}
for(int i = 0;i * i <= val;i++)
{
if(val - i * i >= 0)
{
x[k] = i;
dfs(k + 1, val - i * i);
if(flag)
return ;
}
}
}
int main()
{
int n;
cin >> n;
dfs(1, n);
return 0;
}
9.交换瓶子
有N个瓶子,编号 1 ~ N,放在架子上。
比如有5个瓶子:
2 1 3 5 4
要求每次拿起2个瓶子,交换它们的位置。
经过若干次后,使得瓶子的序号为:
1 2 3 4 5
对于这么简单的情况,显然,至少需要交换2次就可以复位。
如果瓶子更多呢?你可以通过编程来解决。
输入格式为两行:
第一行: 一个正整数N(N<10000), 表示瓶子的数目
第二行:N个正整数,用空格分开,表示瓶子目前的排列情况。
输出数据为一行一个正整数,表示至少交换多少次,才能完成排序。
例如,输入:
5
3 1 2 5 4
程序应该输出:
3
再例如,输入:
5
5 4 3 2 1
程序应该输出:
2
资源约定:
峰值内存消耗 < 256M
CPU消耗 < 1000ms
请严格按要求输出,不要画蛇添足地打印类似:“请您输入…” 的多余内容。
所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。
注意: main函数需要返回0
注意: 只使用ANSI C/ANSI C++ 标准,不要调用依赖于编译环境或操作系统的特殊函数。
注意: 所有依赖的函数必须明确地在源文件中 #include , 不能通过工程设置而省略常用头文件。
提交时,注意选择所期望的编译器类型。
【思路】
这题一开始也是没做出来,想到动态规划上面去了。后来网上查了查,发现竟然真的是贪心。。。选择排序。其实,我也想过,就是直接把不在正确位置的瓶子跟应该放在此位置的瓶子交换,但我不知道如何证明,所以就没做。。。
关于贪心算法的证明,确实挺麻烦的,我看网上也没谁能证出来。反正又给我提供了一种思路哈哈,就是一旦有贪心的思路,就可以去做,一般情况下,可以对一部分数据,总比你空着好吧!
#include<iostream>
using namespace std;
const int maxn = 10005;
int a[maxn];
bool tag = false;
int cnt = 0;
void Greedy(int n)
{
for(int i = 1;i <= n;i++)
{
tag = false;
if(a[i] == i) continue;
else
{
for(int j = i;j <= n && !tag;j++)
{
if(a[j] == i)
{
int temp = a[i];
a[i] = a[j];
a[j] = temp;
tag = true;
cnt++;
}
}
}
}
}
int main()
{
int n;
cin >> n;
for(int i = 1;i <= n;i++)
{
cin >> a[i];
}
Greedy(n);
cout << cnt << endl;
return 0;
}
最后一题就先不放了,目前还不会。反正我的战绩是前5题全对,第6题遗憾的错了,第7题没写出来,第8题写出来了,第9题考试时因为不会证明也没写,最后一题没写。大概就是对6题不到的样子。。。
这次真题训练感觉还是很有难度的啊,蓝桥杯备战要抓紧!