蓝桥杯2016年第七届C/C++ B组省赛习题题解

目录

第一题:煤球数目(简单数学找规律)

第二题:生日蜡烛(暴力枚举+数学)

第三题:凑算式(排列组合+暴力枚举)

第四题:快速排序(送分)

第五题:抽签(dfs)

第六题:方格填数(究极暴力+排列)

第七题:剪邮票(连通块+dfs)

第八题:四平方和(数学+二分)

第九题:交换瓶子(数学)

第十题:最大比例(等比数列+数论)


题目来源:

2016年第七届C/C++ B组蓝桥杯省赛真题_元气算法的博客-CSDN博客


第一题:煤球数目(简单数学找规律)

 

 分析:

(1)1=1

(2)3=1+2

(3)6=1+2+3

(4)10=1+2+3+4

需要注意的是,题目所求的是100层及以上煤球的总数量

#include<iostream>
using namespace std;
int main()
{
	long long sum = 0;
	int i = 0;
	for (int i = 1; i <= 100; i++)
	{
		for (int j = 1; j <= i; j++)
		{
			sum += j;
		}
	}

	cout << sum << endl;//171700

	return 0;
}

第二题:生日蜡烛(暴力枚举+数学)

 核心思路:

外层for循环枚举,从什么时候开始过生日,内层for+1枚举,直到总和==236,跳出循环,输出外层for循环枚举的变量值即可

#include<iostream>
using namespace std;
int main()
{
	for (int i = 1; i <= 100; i++)
	{
		long long sum = 0;//注意细节即可
		for (int j = i; j <= 100; j++)
		{
			sum += j;
			if (sum == 236)
			{
				cout << i << endl;
				return 0;
			}
		}
	}

	return 0;
}

第三题:凑算式(排列组合+暴力枚举)

 

 

#include<iostream>
#include<algorithm>
#include<cmath>

using namespace std;

int main()
{
	int num[9] = { 1,2,3,4,5,6,7,8,9 };
	int cnt = 0;
	do
	{
		float a = num[0];
		float b = num[1] * 1.0 / num[2];
		float c = (num[3] * 100.0 + num[4] * 10 + num[5]) / (num[6] * 100 + num[7] * 10 + num[8]);

		if (fabs(a + b + c - 10) <= 1e-5)//浮点数判断等于的方法:小于一个很小的即可
		{
			cnt++;
		}
	} while (next_permutation(num, num + 9));
	cout << cnt << endl;
	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,p,j);

第五题:抽签

 

 

#include<iostream>
#include<cstdio>
using namespace std;
#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';
		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;
}

解释看到return,以及题意,顿时就会联想到dfs,那么就可以知道了,第一个参数必然是数组a,最后一个参数必然是数组b,这些都没得跑了

那么看到第一层的for循环,就可以知道,它在枚举参赛队伍的编号,所以k就是代表队伍编号的意思,与数组下标同理,那么枚举完这个队伍,肯定要向下一层枚举,所以k+1

看到main函数里:第一开始枚举的时候第三个参数传的是 M :5 ,回看题目,可以知道这是一支五人的队伍,那么随着枚举次数的增加,所以m的真实含义是剩余的人数含义,

f(a, k+1, m-i, b);  //填空位置

第六题:方格填数(究极暴力+排列)

 题解来自:

第七届蓝桥杯 ——方格填数_业余算法学徒的博客-CSDN博客

 

#include<iostream>
#include<algorithm>
using namespace std;
 
int a[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};

int main()
{	
	int ans = 0;
	do
	{
		if(abs(a[0] - a[1]) != 1 && abs(a[0] - a[3]) != 1 && abs(a[0] - a[4]) != 1 && abs(a[0] - a[5]) != 1 &&
		   abs(a[1] - a[2]) != 1 && abs(a[1] - a[4]) != 1 && abs(a[1] - a[5]) != 1 && abs(a[1] - a[6]) != 1 && 
           abs(a[2] - a[5]) != 1 && abs(a[2] - a[6]) != 1 && 
		   abs(a[3] - a[4]) != 1 && abs(a[3] - a[7]) != 1 && abs(a[3] - a[8]) != 1 && 
		   abs(a[4] - a[5]) != 1 && abs(a[4] - a[7]) != 1 && abs(a[4] - a[8]) != 1 && abs(a[4] - a[9]) != 1 && 
		   abs(a[5] - a[6]) != 1 && abs(a[5] - a[8]) != 1 && abs(a[5] - a[9]) != 1 && 
		   abs(a[6] - a[9]) != 1 && 
           abs(a[7] - a[8]) != 1 &&
           abs(a[8] - a[9]) != 1) ans ++;

	}while(next_permutation(a, a + 10));
	
	cout << ans << endl;
	return 0;
}

第七题:剪邮票

 

 

#include<iostream>
using namespace std;
const int N = 15;

int ans;
int p[N];
int e[N][N];
bool used[N];

int find(int x)
{
	if (p[x] != x) p[x] = find(p[x]);
	return p[x];
}

void dfs(int u, int start)
{
	if (u == 5)
	{
		for (int i = 1; i <= 12; i++) p[i] = i;

		for (int i = 1; i <= 12; i++)
		{
			for (int j = 1; j <= 12; j++)
			{
				if (e[i][j] && used[i] && used[j])
				{
					p[find(i)] = find(j);
				}
			}
		}
		int cnt = 0;
		for (int i = 1; i <= 12; i++)
		{
			if (used[i] && p[i] == i)
			{
				cnt++;
			}
		}
		if (cnt == 1) ans++;
		return;
	}

	for (int i = start; i <= 12; i++)
	{
		if (!used[i])
		{
			used[i] = true;
			dfs(u + 1, i + 1);
			used[i] = false;
		}
	}
}

int main()
{
	e[1][2] = e[1][5] = 1;
	e[2][1] = e[2][3] = e[2][6] = 1;
	e[3][2] = e[3][4] = e[3][7] = 1;
	e[4][3] = e[4][8] = 1;
	e[5][1] = e[5][6] = e[5][9] = 1;
	e[6][2] = e[6][5] = e[6][7] = e[6][10] = 1;
	e[7][3] = e[7][6] = e[7][8] = e[7][11] = 1;
	e[8][4] = e[8][7] = e[8][12] = 1;
	e[9][5] = e[9][10] = 1;
	e[10][6] = e[10][9] = e[10][11] = 1;
	e[11][7] = e[11][10] = e[11][12] = 1;
	e[12][8] = e[12][11] = 1;

	dfs(0, 1);

	cout << ans << endl;

	return 0;
}

第八题:四平方和(数学+二分)

 

 

#include <cstring>
#include <iostream>
#include <algorithm>
#include <cmath>

using namespace std;

const int N = 2500010;

struct Sum
{
    int s, c, d;
    bool operator< (const Sum& t)const
    {
        if (s != t.s) return s < t.s;
        if (c != t.c) return c < t.c;
        return d < t.d;
    }
}sum[N];

int n, m;

int main()
{
    cin >> n;

    for (int c = 0; c * c <= n; c++)
        for (int d = c; c * c + d * d <= n; d++)
            sum[m++] = { c * c + d * d, c, d };

    sort(sum, sum + m);

    for (int a = 0; a * a <= n; a++)
        for (int b = 0; a * a + b * b <= n; b++)
        {
            int t = n - a * a - b * b;
            int l = 0, r = m - 1;
            while (l < r)
            {
                int mid = l + r >> 1;
                if (sum[mid].s >= t) r = mid;
                else l = mid + 1;
            }
            if (sum[l].s == t)
            {
                printf("%d %d %d %d\n", a, b, sum[l].c, sum[l].d);
                return 0;
            }
        }

    return 0;
}


第九题:交换瓶子(数学)

 

 

#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 10010;

int n;
int b[N];
bool st[N];

int main()
{
	cin >> n;
	for (int i = 1; i <= n; i++) cin >> b[i];

	int cnt = 0;
	for (int i = 1; i <= n; i++)
	{
		if (!st[i])
		{
			cnt++;//判环个数
			for (int j = i; !st[j]; j = b[j])
			{
				st[j] = true;
			}
		}
	}
	printf("%d\n", n - cnt);//次数=数组元素总个数-环个数

	return 0;
}

第十题:最大比例(等比数列+数论)

 

 

 

#include<iostream>
#include<algorithm>


using namespace std;

typedef long long LL;

const int N = 110;

int n;
LL x[N];//存放输入的数字 
LL a[N], b[N];//分别表示分子和分母

LL gcd(LL a, LL b)//辗转相除
{
    return b ? gcd(b, a % b) : a;
}

LL gcd_sub(LL a, LL b)//更相减损
{
    if (b > a)swap(a, b);
    if (b == 1)return a;
    return gcd_sub(b, a / b);
}
int main()
{
    cin >> n;
    for (int i = 0; i < n; i++)cin >> x[i];//读入

    sort(x, x + n);//排序,方便找到首项

    LL dd = 0;
    int cnt = 0;
    for (int i = 1; i < n; i++)
    {
        if (x[i] != x[i - 1])//去重:重复的不计入考虑范围
        {
            dd = gcd(x[i], x[0]);//最大公约数
            a[cnt] = x[i] / dd;//a[1]=x[i]/dd
            b[cnt] = x[0] / dd;
            cnt++;
        }
    }

    LL up = a[0], down = b[0];//up分子 down分母
    for (int i = 1; i < cnt; i++)//分开求分子分母的指数最大公约数
    {
        up = gcd_sub(up, a[i]);
        down = gcd_sub(down, b[i]);
    }

    cout << up << "/" << down;

    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值