第七届蓝桥杯真题总结

第一题  煤球数目

有一堆煤球,堆成三角棱锥形。具体:
第一层放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("\n");

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("\n");
    
    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\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;
}
#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\n",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\n", 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\n",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;
}

 

 

 

 

 

 

 

 

 

 

posted @ 2018-03-21 00:14  douzujun  阅读(1016)  评论(0编辑  收藏  举报