第一题 煤球数目
有一堆煤球,堆成三角棱锥形。具体:
第一层放1个,
第二层3个(排列成三角形),
第三层6个(排列成三角形),
第四层10个(排列成三角形),
....
如果一共有100层,共有多少个煤球?
请填表示煤球总数目的数字。
注意:你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。
题解:注意题目说的是100层,一共有多少个啊。。规律蛮简单的,蓝桥杯第一题就找规律;不要想复杂了;第n层:(1+n)*n/2;
#include <iostream>
#include <cstdio>
#include <cstdlib>
using namespace std;
typedef long long LL;
void solve()
{
int n;
cin >> n;
LL ans = 0;
for (int i = 1; i <= n; i++)
{
ans += (1 + i) * i / 2;
}
cout << ans << endl;
}
int main()
{
solve();
return 0;
}
答案:171700
第二题:
生日蜡烛
某君从某年开始每年都举办一次生日party,并且每次都要吹熄与年龄相同根数的蜡烛。
现在算起来,他一共吹熄了236根蜡烛。
请问,他从多少岁开始过生日party的?
请填写他开始过生日party的年龄数。
注意:你提交的应该是一个整数,不要填写任何多余的内容或说明性文字
#include <iostream>
using namespace std;
void solve()
{
for (int s = 1; s <= 100; s++)
{
for (int e = s; e <= 100; e++)
{
int sum = 0;
for (int i = s; i <= e; i++)
{
sum += i;
}
if (sum == 236) {
cout << s << " " << e << endl;
}
}
}
}
int main()
{
solve();
return 0;
}
第三题 凑算式
B DEF
A + --- + --——— = 10
C GHI
(如果显示有问题,可以参见【图1.jpg】)
这个算式中A~I代表1~9的数字,不同的字母代表不同的数字。
比如:
6+8/3+952/714 就是一种解法,
5+3/1+972/486 是另一种解法。
这个算式一共有多少种解法?
注意:你提交应该是个整数,不要填写任何多余的内容或说明性文字。
题解:全排列问题,注意,能不用除法就不用除法,可以转换为乘法。或者除的时候用double类型。
#include <iostream>
#include <algorithm>
using namespace std;
int a[] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
void solve()
{
int res = 0;
do {
int A = a[0], B = a[1], C = a[2];
int DEF = a[3]*100 + a[4]*10 + a[5];
int GHI = a[6]*100 + a[7]*10 + a[8];
int ans = (B*GHI + DEF*C);
if (ans == (10 - A)*(C*GHI)) {
res++;
}
} while (next_permutation(a, a + 9));
cout << res << endl;
}
int main()
{
solve();
return 0;
}
手写全排列方法:
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <cstring>
using namespace std;
int ans;
const int maxn = 20;
int num[maxn];
bool vis[maxn];
void judge()
{
double sum = num[0] + (double)num[1] / num[2] + (double)(num[3]*100+num[4]*10+num[5]) /
(num[6]*100 + num[7]*10 + num[8]);
if (sum == 10){
ans++;
}
}
void dfs(int cur)
{
if (cur == 9) {
judge();
return;
}
for (int i = 1; i <= 9; i++)
{
if (!vis[i])
{
num[cur] = i;
vis[i] = true;
dfs(cur + 1);
vis[i] = false;
}
}
}
void solve()
{
memset(vis, 0, sizeof(vis));
dfs(0);
cout << ans << endl;
}
int main()
{
solve();
return 0;
}
第四题 快速排序
排序在各种场合经常被用到。
快速排序是十分常用的高效率的算法。
其思想是:先选一个“标尺”,
用它把整个队列过一遍筛子,
以保证:其左边的元素都不大于它,其右边的元素都不小于它。
这样,排序问题就被分割为两个子区间。
再分别对子区间排序就可以了。
下面的代码是一种实现,请分析并填写划线部分缺少的代码。
#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("
");
return 0;
}
注意:只填写缺少的内容,不要书写任何题面已有代码或说明性文字。
解答:swap(a, j, p);
#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);
}
swap(a, j, p);
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("
");
return 0;
}
第五题: 抽签
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
",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;
}
#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;
//N为6个国
//M为5个人
//m为剩余人数
if(k == N){
b[M] = 0;
if(m == 0) printf("%s
",b);
return;
}
for(i=0; i<=a[k]; i++){
for(j=0; j<i; j++)
b[M-m+j] = k + 'A';
//下一个国, 剩余 m - i人
f(a, k+1, m - i, b); //填空位置
}
}
int main()
{
int a[N] = {4,2,2,1,1,3};
char b[BUF];
f(a, 0, M, b);
return 0;
}
第六题: 方格填数
如下的10个格子
(如果显示有问题,也可以参看【图1.jpg】)
填入0~9的数字。要求:连续的两个数字不能相邻。
(左右、上下、对角都算相邻)
一共有多少种可能的填数方案?
请填写表示方案数目的整数。
注意:你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。
#include <iostream>
#include <cmath>
#include <fstream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <algorithm>
using namespace std;
const int INF = 10000000;
const int ROW = 3, COL = 4;
int dir[8][2] = {{-1, 0}, {-1, 1}, {0, 1}, {1, 1},
{1, 0}, {1, -1}, {0, -1}, {-1, -1}};
int ans;
int maze[ROW][COL];
void input();
bool check( int r, int c);
bool judge(int r, int c);
void solve();
int a[10] = {0, 1, 2, 3, 4 ,5 , 6, 7 ,8 ,9};
void input()
{
maze[0][0] = maze[2][3] = INF;
}
bool judge(int r, int c)
{
return (r >= 0 && r < 3) && (c >= 0 && c < 4);
}
//判断
bool check(int r, int c)
{
//当前位置为 (r, c)是空位置...也就是说 和周围不连续
if ((r == 0 && c == 0) || (r == 2 && c == 3)) return true;
for (int k = 0; k < 8; k++) {
int nx = r + dir[k][0], ny = c + dir[k][1];
if (judge(nx, ny) && abs(maze[nx][ny] - maze[r][c]) == 1) {
return false;
}
}
return true;
}
bool check2()
{
int i, j;
for (i = 1; i < COL; i++) {
maze[0][i] = a[i-1];
}
for (j = 0; j < COL; j++) {
maze[1][j] = a[COL + j - 1];
}
for (j = 0; j < COL - 1; j++) {
maze[2][j] = a[COL * 2 + j - 1];
}
for (i = 0; i < ROW; i++) {
for (j = 0; j < COL; j++) {
//不相邻,且
if (!check(i, j)) { //&& (i != 0 || j != 0) && (i != 2 || j != 3)
return false;
}
}
}
return true;
}
void solve()
{
input();
do {
if (check2()) {
ans++;
}
} while (next_permutation(a, a + 10));
cout << ans << endl;
}
int main()
{
solve();
return 0;
}
第七题:剪邮票
如【图1.jpg】, 有12张连在一起的12生肖的邮票。
现在你要从中剪下5张来,要求必须是连着的。
(仅仅连接一个角不算相连)
比如,【图2.jpg】,【图3.jpg】中,粉红色所示部分就是合格的剪取。
请你计算,一共有多少种不同的剪取方法。
请填写表示方案数目的整数。
注意:你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cstdlib>
using namespace std;
const int maxn = 14;
int maze[3][4];
int num[6];
int have[13]; // 用了对从全排列中 选出来 5个数 ,进行 标志 (回溯: 标志为true后,需要换回false)
bool used[3][4]; //这个是 从全排列中选出来5个数,进行DFS搜索是否连续用的标志数组 , 标志为true后,不需要换回false
bool visit[13]; //进行全排列用的标志数组
int ans;
int Count = 0;
int dir[4][2] = {{-1, 0}, {0, 1}, {1, 0}, {0, -1}}; //方向
void init();
void dfs_find(int r, int c);
bool judge(int r, int c);
void solve();
void init()
{
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 4; j++) {
maze[i][j] = i*4 + j + 1;
}
}
}
bool judge(int r, int c)
{
return (r >= 0 && r < 3) && (c >= 0 && c < 4);
}
void dfs_find(int r, int c)
{
for (int i = 0; i < 4; i++)
{
int nx = r + dir[i][0], ny = c + dir[i][1];
//这个位置不是have标记位置(have里标记过的元素,是全排列找到的五个元素),或者已经访问过了
if (judge(nx, ny) && !used[nx][ny] && have[maze[nx][ny]]) {
used[nx][ny] = true; //不需要换回 false, 除非出现另外一组5个数的时候
Count++; //连续的数++
dfs_find(nx, ny); //对一个点进行DFS
}
}
}
void solve()
{
memset(have, 0, sizeof(have));
memset(used, false, sizeof(used));
for (int i = 1; i <= 5; i++) {
have[ num[i] ] = 1; //对5个数的位置进行标记
}
for (int i = 0; i < 12; i++)
{
int r = i / 4; //对应行
int c = i % 4; //对应列
if ( have[maze[r][c]] ) // 对找到的 5个数字(被标记1的),开始DFS搜索
{
Count = 1; //开始为1
used[r][c] = true; //由标记的第一个数开始, 向其他标记的数 进行DFS, 找到则 Count++
dfs_find(r, c);
break;
}
}
if (Count == 5) { //全排列找到的5个数, 是相邻的, 则ans++
ans++;
}
}
//创建5个数的组合
void Start_DFS(int cur)
{
if (cur == 6) //找到了5个数
{
solve(); //对找到的5个数,进行排列组合
return;
}
//1到12 这 12个数 挨个遍历 -- 并进行DFS搜索
for (int i = num[cur - 1] + 1; i < 13; i++)
{
if (!visit[i])
{
visit[i] = true;
num[cur] = i; //存数, 对12个数进行全排列,从中选5个数,再进行排列组合
Start_DFS(cur + 1); //下一个数
visit[i] = false;
}
}
}
int main()
{
init();
Start_DFS(1);
printf("%d
", ans);
}
算法思路:
1. 先全排列,从全排列1~12,从中选5个数,进行排列组合;
2. 对选中的5个数标志;
3. 循环找到第一个 第一个被标志的位置,并DFS递归寻找,他的dir方向的数字,是否是从全排列中选出来的其他数字.
详细看注释.
第八题 四平方和
四平方和定理,又称为拉格朗日定理:
每个正整数都可以表示为至多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
解答:可能会超时.......但是这里秒出结果了...
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
using namespace std;
void solve()
{
int N;
cin >> N;
//1150*1150*4 = 5290000
for (int a = 0; a <= 1150; a++)
{
if (a*a >= N) continue;
for (int b = a; b <= 1150; b++)
{
if (a*a + b*b >= N) continue;
for (int c = b; c <= 1150; c++)
{
if (a*a + b*b + c*c >= N) continue;
double d = sqrt(N - a*a - b*b - c*c);
if (d == (int)d) {
printf("%d %d %d %.f
",a,b,c, d);
return;
}
}
}
}
}
int main()
{
solve();
return 0;
}
第九题: 交换瓶子
有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
题解:感觉是一个选择排序......不知道对不对.....
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const int maxn = 10000 + 20;
int num[maxn];
void solve()
{
int N;
int ans = 0;
scanf("%d", &N);
for (int i = 0; i < N; i++)
{
scanf("%d", &num[i]);
}
for (int i = 0; i < N - 1; i++)
{
int min = i;
for (int j = min + 1; j < N; j++)
{
if (num[min] > num[j]) {
min = j;
}
}
if (min != i) {
swap(num[min], num[i]);
ans++;
}
}
// for (int i = 0; i < N; i++) {
// cout << num[i] << " ";
// }
// cout << endl;
cout << ans << endl;
}
int main()
{
solve();
return 0;
}