Bootstrap

2015年蓝桥杯第六届C&C++大学B组真题及代码

目录

 1A:奖券数目(填空_简单枚举)

2B:星系炸弹(填空_日期计算)

3C:三羊献瑞(填空_全排列)

4D:格子中输出(代码填空)

5E:九数组分数(代码填空)

6F:加法变乘法(填空)

7G:牌型种数(填空)

8H:移动距离(编程)

解析代码

9I:垒骰子(编程)

解析代码

10J:生命之树(编程)

解析代码( 树形DP)


 1A:奖券数目(3分填空_简单枚举)

题目分析:简单的循环枚举。答案52488

#include<iostream>
using namespace std;

bool check(int num)
{
	while (num)
	{
		int j = num % 10;
		if (j == 4)
			return false;
		num /= 10;
	}
	return true;
}

int main()
{
	int cnt = 0;
	for (int i = 10000; i <= 99999; ++i)
	{
		if (check(i)) 
			++cnt;
	}
	cout << cnt << endl;
	return 0;
}
// 答案52488

2B:星系炸弹(5分填空_日期计算)

题目解析:

打开计算器两步搞定:答案2017-08-05

但还是贴个代码:

#include<iostream>
using namespace std;
int months[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };
bool is_leap(int year)
{
	return (year % 400 == 0 || (year % 100 != 0 && year % 4 == 0));
}
int main()
{
	int year = 2014;
	int month = 11;
	int day = 9;
	int T = 1000;
	while (T--)
	{
		day++;
		if (month == 2)
		{
			if (is_leap(year)) months[2] = 29;//如果是闰年
		}
		if (day > months[month])//如果天数已经大于该月的天数时
		{
			if (month == 12)//如果该月是12月,那么就++年
			{
				year++;
				month = 1;//月份重新变为1
				day = 1;
			}
			else
			{
				++month; // 否则只是月份++
				day = 1;
			}
		}
		months[2] = 28;//还原
	}
	printf("%d-%02d-%02d\n", year, month, day);//2017-08-05
	return 0;
}

3C:三羊献瑞(9分填空_全排列)

        从文字中可以得出 祥 三 为非零的数,且  为1。这里可以用暴力,7层循环,具体不写了。这里使用全排列算法实现,数组中:num[0]~num[6]分别代表 祥 瑞 生 辉 羊 献 气

答案1085

#include <iostream>
#include <algorithm>
using namespace std;
int main()
{
	int num[9] = { 0,2,3,4,5,6,7,8,9 };
	do {
		if (num[0] != 0)//数字的开头不能为0
		{
			int a = num[0] * 1000 + num[1] * 100 + num[2] * 10 + num[3];
			int b = 1000 + num[4] * 100 + num[5] * 10 + num[1];
			int c = 10000 + num[4] * 1000 + num[2] * 100 + num[1] * 10 + num[6];
			if (a + b == c)
			{
				cout << "1" << num[4] << num[5] << num[1] << endl;
				break; // 答案1085
			}
		}
	} while (next_permutation(num, num + 9));
	return 0;
}

4D:格子中输出(11分代码填空)

题目描述:

StringInGrid函数会在一个指定大小的格子中打印指定的字符串。
要求字符串在水平、垂直两个方向上都居中。
如果字符串太长,就截断。
如果不能恰好居中,可以稍稍偏左或者偏上一点。
下面的程序实现这个逻辑,请填写划线部分缺少的代码。

#include <stdio.h>
#include <string.h>

void StringInGrid(int width, int height, const char* s)
{
	int i,k;
	char buf[1000];
	strcpy(buf, s);
	if(strlen(s)>width-2) buf[width-2]=0;
	
	printf("+");
	for(i=0;i<width-2;i++) printf("-");
	printf("+\n");
	
	for(k=1; k<(height-1)/2;k++){
		printf("|");
		for(i=0;i<width-2;i++) printf(" ");
		printf("|\n");
	}
	
	printf("|");
	
	printf("%*s%s%*s",_____________________________________________);  //填空
	          
	printf("|\n");
	
	for(k=(height-1)/2+1; k<height-1; k++){
		printf("|");
		for(i=0;i<width-2;i++) printf(" ");
		printf("|\n");
	}	
	
	printf("+");
	for(i=0;i<width-2;i++) printf("-");
	printf("+\n");	
}

int main()
{
	StringInGrid(20,6,"abcd1234");
	return 0;
}


题目解析:

        就是要控制这个字符串在中间输出。因为这两行两边有两个字符,所以字符串剩余的空间,就是总的宽度width减减去字符串的,再减去两边方框的字符,然后再除二即可,然后因为存在基数的情况,所以还会有后面的考虑。

        此外:使用%*s,表示这里的具体域宽值由后面的实参决定,如printf(“%*s”,6, “abc”)就是把”abc”放到在域宽为6的空间中右对齐。 *就是用来控制域宽而已。

答案:

(width-2-strlen(s))/2," ",s,width-2-strlen(s)-(width-2-strlen(s))/2," "

5E:九数组分数(13分代码填空)

题目描述:
1,2,3…9 这九个数字组成一个分数,其值恰好为1/3,如何组法?
下面的程序实现了该功能,请填写划线部分缺失的代码。

#include <stdio.h>
void test(int x[])
{
	int a = x[0]*1000 + x[1]*100 + x[2]*10 + x[3];
	int b = x[4]*10000 + x[5]*1000 + x[6]*100 + x[7]*10 + x[8];
	
	if(a*3==b) printf("%d / %d\n", a, b);
}

void f(int x[], int k)
{
	int i,t;
	if(k>=9){
		test(x);
		return;
	}
	
	for(i=k; i<9; i++){
		{t=x[k]; x[k]=x[i]; x[i]=t;}
		f(x,k+1);
		_____________________________________________ // 填空处
	}
}
	
int main()
{
	int x[] = {1,2,3,4,5,6,7,8,9};
	f(x,0);	
	return 0;
}

题目解析:

        这题按照固定思维,我第一次想到的就是填空处是一个递归,然而,我看到递归外面有一个for循环,对于这种for循环的递归,一般只有一个出入口,那么这个填空处就不是填递归函数入口,{t=x[k]; x[k]=x[i]; x[i]=t;}表示的在进入递归前需要进行交换值,那么我们想想,如果递归进去后,再出来,发现不满足值,是不是需要进行一个值的还原,所以接着使用{t=x[k]; x[k]=x[i]; x[i]=t;}进行还原,这题考察对于递归的熟练程度。。答案:

{t=x[k]; x[k]=x[i]; x[i]=t;}

题目解析:

        这里使用递归的猜想,对于这里,我们要修改的就是递归函数里后面两个参数里的三个变量col,row,w,这里使用的方法是修改参数,然后通过结果发现,col控制列,col控制行,w控制空格数,所以最后调调答案就出来了,这种递归题在蓝桥杯中通过边调试边看结果最快。

所以三层递归就是这个意思:

	f(a, rank - 1, row, col + w / 2); // 处理最上面的三角形
	f(a, rank - 1, row + w / 2, col); // 处理左下角三角形
	f(a, rank - 1, row + w / 2, col + w); // 处理右下角三角形

答案:

f(a, rank-1, row, col + w / 2)

6F:加法变乘法(17分填空)

题目描述:

我们都知道:1+2+3+ … + 49 = 1225
现在要求你把其中两个不相邻的加号变成乘号,使得结果为2015
比如:
1+2+3+…+10*11+12+…+27*28+29+…+49 = 2015
就是符合要求的答案。请你寻找另外一个可能的答案,并把位置靠前的那个乘号左边的数字提交(对于示例,就是提交10)。
注意:需要你提交的是一个整数,不要填写任何多余的内容。

题目分析:

        暴力枚举,这里的话将乘号的位置看做是要遍历的变量,一共两个值。知道两个乘号的位置,然后模拟计算就可以了。

答案16

#include<iostream>
using namespace std;

int main()
{
	for (int i = 1; i < 49; i++) // 第一个*的位置 
	{
		for (int j = i + 2; j < 49; j++) // 第二个*的位置 
		{
			int sum = 0;
			for (int k = 1; k < 50; ++k) // 进行运算 
			{
				if (k == i || k == j)
				{
					sum += k * (k + 1);
					++k;
				}
				else
					sum += k;
			}
			if (sum == 2015)
			{
				cout << i << " " << j << endl;
			}
		}
	}
	return 0;
}

7G:牌型种数(21分填空)

题目描述:
小明被劫持到X赌城,被迫与其他3人玩牌。
一副扑克牌(去掉大小王牌,共52张),均匀发给4个人,每个人13张。
这时,小明脑子里突然冒出一个问题:
如果不考虑花色,只考虑点数,也不考虑自己得到的牌的先后顺序,自己手里能拿到的初始牌型组合一共有多少种呢?
请填写该整数,不要填写任何多余的内容或说明文字。

题目解析:

答案3598180

dfs代码:

#include <iostream>
#include <algorithm>
using namespace std;
int num[9] = { 2,4,5,6,7,9,10,11,12 };
bool jude() // 判断六条直线是否相等
{
	int ans1 = 1 + num[1] + num[4] + num[8];
	int ans2 = 1 + num[0] + num[3] + num[5];
	int ans3 = 8 + num[0] + num[1] + num[2];
	int ans4 = 8 + num[3] + num[6] + 3;
	int ans5 = 3 + num[7] + num[4] + num[2];
	int ans6 = num[5] + num[6] + num[7] + num[8];
	return ans1 == ans2 && ans1 == ans3 && ans1 == ans4 && ans1 == ans5 && ans1 == ans6;
}
int main()
{
	do
	{
		if (jude())
			break;
	} while (next_permutation(num, num + 9));
	cout << num[3] << endl;
	return 0;
}

8H:移动距离(15分编程)

题目描述:

        X星球居民小区的楼房全是一样的,并且按矩阵样式排列。其楼房的编号为1,2,3…
当排满一行时,从下一行相邻的楼往反方向排号。
比如:当小区排号宽度为6时,开始情形如下:
1 2 3 4 5 6
12 11 10 9 8 7
13 14 15 …
        我们的问题是:已知了两个楼号m和n,需要求出它们之间的最短移动距离(不能斜线方向移动)

输入为3个整数w m n,空格分开,都在1到10000范围内
w为排号宽度,m,n为待计算的楼号。
要求输出一个整数,表示m n 两楼间最短移动距离。

例如:
用户输入:
6 8 2
则,程序应该输出:
4

再例如:
用户输入:
4 7 20
则,程序应该输出:
5

资源约定:
峰值内存消耗 < 256M
CPU消耗 < 1000ms


解析代码

题目分析:

        先算纵向距离,再算横向距离,通过行数的差的奇偶判断行序是否一致(升序降序)。一致的话取余相减即可,主要是不一致的情况,这部分没有什么推理,凭借简单的小学数学逻辑代数硬推的。

#include <bits/stdc++.h>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std;

int main()
{
	int w, m, n;
	cin >> w >> m >> n;
	--m; // 为了对应
	--n;
	int x1 = m / w, x2 = n / w;
	int y1 = m % w, y2 = n % w;
	if (x1 % 2 != 0) // 奇偶情况
		y1 = w - 1 - y1;
	if (x2 % 2 != 0)
		y2 = w - 1 - y2;
	cout << abs(x1 - x2) + abs(y1 - y2) << endl;
	return 0;
}

9I:垒骰子(25分编程)

题目描述:

        X 国王有一个地宫宝库。是 n x m 个格子的矩阵。每个格子放一件宝贝。每个宝贝贴着价值标签。地宫的入口在左上角,出口在右下角。小明被带到地宫的入口,国王要求他只能向右或向下行走。走过某个格子时,如果那个格子中的宝贝价值比小明手中任意宝贝价值都大,小明就可以拿起它(当然,也可以不拿)。当小明走到出口时,如果他手中的宝贝恰好是k件,则这些宝贝就可以送给小明。请你帮小明算一算,在给定的局面下,他有  多少种不同的行动方案能获得这k件宝贝。

【数据格式】
        输入一行3个整数,用空格分开:n m k (1<=n,m<=50, 1<=k<=12)接下来有 n 行数据,每行有 m 个整数 Ci (0<=Ci<=12)代表这个格子上的宝物的价值要求输出一个整数,表示正好取k个宝贝的行动方案数。该数字可能很大,输出它对 1000000007 取模的结果。

例如,输入:
2 2 2
1 2
2 1
程序应该输出:
2

再例如,输入:
2 3 2
1 2 3
2 1 5
程序应该输出:
14

资源约定:
峰值内存消耗(含虚拟机) < 256M
CPU消耗 < 2000ms


解析代码

题目解析:

AcWing 1217. 垒骰子 - AcWing

第六届蓝桥杯【省赛试题9】垒骰子 ( 矩阵快速幂 )-CSDN博客

待续

10J:生命之树(31分编程)

题目描述:

        在X森林里,上帝创建了生命之树。他给每棵树的每个节点(叶子也称为一个节点)上,都标了一个整数,代表这个点的和谐值。
        上帝要在这棵树内选出一个非空节点集S,使得对于S中的任意两个点a,b,都存在一个点列 {a, v1, v2, …, vk, b} 使得这个点列中的每个点都是S里面的元素,且序列中相邻两个点间有一条边相连。
        在这个前提下,上帝要使得S中的点所对应的整数的和尽量大。这个最大的和就是上帝给生命之树的评分。经过atm的努力,他已经知道了上帝给每棵树上每个节点上的整数。但是由于 atm 不擅长计算,他不知道怎样有效的求评分。他需要你为他写一个程序来计算一棵树的分数。

「输入格式」
第一行一个整数 n 表示这棵树有 n 个节点。
第二行 n 个整数,依次表示每个节点的评分。
接下来 n-1 行,每行 2 个整数 u, v,表示存在一条 u 到 v 的边。由于这是一棵树,所以是不存在环的。

「输出格式」
输出一行一个数,表示上帝给这棵树的分数。

「样例输入」
5
1 -2 -3 4 5
4 2
3 1
1 2
2 5

「样例输出」
8

「数据范围」
对于 30% 的数据,n <= 10
对于 100% 的数据,0 < n <= 10^5, 每个节点的评分的绝对值不超过 10^6 。

资源约定:
峰值内存消耗 < 256M
CPU消耗 < 3000ms


解析代码( 树形DP)

 树形DP:

(1)dp数组的定义:表示以u为根节点的子树中所有连通块的的权值的最大值

(2)dp数组的属性:最大值

(3)dp数组的递推公式:如果大于0,则把它加入dp数组中,核心就是贪心的思想,因为要求的是连通块的最大值

  • dp[1]是:以1为根节点,包括1的所有联通块的最大值
  • dp[2]是:以2为根节点,包括2的所有连通块的最大值(注意此时不包括1)
  • dp[3]是:以3为根节点,包括3的所有连通块的最大值(注意此时不包括1)

        同理dp[4]=4  dp[5]=5(也就是说不能向上寻找只能向下寻找),所以dfs深搜的第一步是:将f[u]=w[u]   (将该根节点的值存入dp数组)。之后才是向下搜索,注意此时的f[j]只是可能是的单个节点的值,它指的是这个节点之下包括这个节点的值,所以是大于0,才把它加入进去。

解析代码( 树形DP)

#include <iostream>
#include <algorithm>
#include <vector>
#include <cmath>
using namespace std;
#define endl '\n'
#define int long long

const int N = 100010, M = N * 2;

int n;
int w[N];
int h[N], e[M], ne[M], idx;
int f[N];

void add(int a, int b)
{
	e[idx] = b;
	ne[idx] = h[a];
	h[a] = idx++;
}

void dfs(int u, int father)
{
	f[u] = w[u];
	for (int i = h[u]; i != -1; i = ne[i])
	{
		int j = e[i];
		if (j != father)
		{
			dfs(j, u);
			f[u] += max(0ll, f[j]);
		}
	}
}

signed main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	cin >> n;
	memset(h, -1, sizeof h);

	for (int i = 1; i <= n; ++i)
	{
		cin >> w[i];
	}
	for (int i = 0; i < n - 1; ++i)
	{
		int a, b;
		cin >> a >> b;
		add(a, b);
		add(b, a);
	}
	dfs(1, -1);
	int res = f[1];
	for (int i = 2; i <= n; ++i)
	{
		res = max(res, f[i]);
	}
	cout << res << endl;
	return 0;
}
;