蓝桥杯 历届B组 程序填空总结(c/c++)

蓝桥杯 历届B组 程序填空总结(c/c++)

本文章中没有涉及到的题目,是因为与本人的另一篇博客 蓝桥杯  历届A组 程序填空总结(c/c++)  题目重复,所以在此就不重复上传。如果需要,自己去找。

目录

蓝桥杯 历届B组 程序填空总结(c/c++)

1. 字符串

2. 关联账户

3. 抽签

4.棋子换位

5. 取数位

6.希尔伯特曲线

7. 快速排序


1. 字符串

输入一个字符串,求它包含多少个单词。单词间以一个或者多个空格分开。
第一个单词前,最后一个单词后也可能有0到多个空格。
比如:" abc    xyz" 包含两个单词,"ab   c   xyz    "  包含3个单词。

如下的程序解决了这个问题,请填写划线部分缺失的代码。

注意:只填写划线部分的代码,不要填写任何多余的内容。比如已经存在的小括号,注释或说明文字等。

int get_word_num(char* buf)
{
	int n = 0;   
	int tag = 1; 
	char* p = buf;
	
	for(;*p!=0 && *p!=13 && *p!=10;p++){
		if(*p==' ' && tag==0) tag=1;
		if( _____________________ ) { n++; tag=0; }   //填空 *p!=' ' &&tag==1
	}
	
	return n;
}

int main()
{
	char buf[1000];
	fgets(buf,1000,stdin);
	
	printf("%d\n", get_word_num(buf));
	return 0;
}

2. 关联账户

为增大反腐力度,某地警方专门支队,对若干银行账户展开调查。

如果两个账户间发生过转账,则认为有关联。如果a,b间有关联, b,c间有关联,则认为a,c间也有关联。

对于调查范围内的n个账户(编号0到n-1),警方已知道m条因转账引起的直接关联。

现在希望知道任意给定的两个账户,求出它们间是否有关联。有关联的输出1,没有关联输出0

小明给出了如下的解决方案:


#include <stdio.h>
#define N 100

int connected(int* m, int p, int q)
{
	return m[p]==m[q]? 1 : 0;
}

void link(int* m, int p, int q)
{
	int i;
	if(connected(m,p,q)) return;
	int pID = m[p];
	int qID = m[q];
	for(i=0; i<N; i++) ______________;  //填空位置  m[i]=(m[i]==qID?pID:m[i]) 并查集思想
}

int main()
{
	int m[N];
	int i;
	for(i=0; i<N; i++) m[i] = i; //初始状态,每个节点自成一个连通域
	link(m,0,1); //添加两个账户间的转账关联
	link(m,1,2); 
	link(m,3,4); 
	link(m,5,6); 
	link(m,6,7); 
	link(m,8,9); 
	link(m,3,7); 
	
	printf("%d ", connected(m,4,7));
	printf("%d ", connected(m,4,5));
	printf("%d ", connected(m,7,9));
	printf("%d ", connected(m,9,2));
	return 0;
}

3. 抽签

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';
		______________________;  //填空位置  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;
}

4.棋子换位

有n个棋子A,n个棋子B,在棋盘上排成一行。
它们中间隔着一个空位,用“.”表示,比如:

AAA.BBB

现在需要所有的A棋子和B棋子交换位置。
移动棋子的规则是:
1. A棋子只能往右边移动,B棋子只能往左边移动。
2. 每个棋子可以移动到相邻的空位。
3. 每个棋子可以跳过相异的一个棋子落入空位(A跳过B或者B跳过A)。

AAA.BBB 可以走法:
移动A ==> AA.ABBB
移动B ==> AAAB.BB

跳走的例子:
AA.ABBB ==> AABA.BB

以下的程序完成了AB换位的功能,请仔细阅读分析源码,填写划线部分缺失的内容。

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

void move(char* data, int from, int to)
{
	data[to] = data[from];
	data[from] = '.';
}

int valid(char* data, int k)
{
	if(k<0 || k>=strlen(data)) return 0;
	return 1;
}
	
void f(char* data)
{
	int i;
	int tag;
	int dd = 0; // 移动方向
	
	while(1){
		tag = 0;
		for(i=0; i<strlen(data); i++){
			if(data[i]=='.') continue;
			if(data[i]=='A') dd = 1;
			if(data[i]=='B') dd = -1;
			
			if(valid(data, i+dd) && valid(data,i+dd+dd) 
			&& data[i+dd]!=data[i] && data[i+dd+dd]=='.'){ 
			//如果能跳... 
				move(data, i, i+dd+dd);
				printf("%s\n", data);
				tag = 1;
				break;
			}
		}
		
		if(tag) continue;
		
		for(i=0; i<strlen(data); i++){
			if(data[i]=='.') continue;
			if(data[i]=='A') dd = 1;
			if(data[i]=='B') dd = -1;			
				 
			if(valid(data, i+dd) && data[i+dd]=='.'){ 
			// 如果能移动...
				if( ______________________ ) continue;  //填空位置 
				move(data, i, i+dd);
				printf("%s\n", data);
				tag = 1;
				break;
			}
		}
		
		if(tag==0) break;					
	}
}
	
int main()
{
	char data[] = "AAA.BBB";	
	f(data);
	return 0;
}

 valid(data, i+dd+dd) && valid(data,i-dd)&&data[i+dd+dd]==data[i-dd] 

手动模拟这个跳的过程会发现一个规律,当能直接平移的时候,必须是“.”的两边有A,B两个不相同的字母 
所以我们就把相同的情况过滤掉。

5. 取数位

求1个整数的第k位数字有很多种方法。
以下的方法就是一种。

// 求x用10进制表示时的数位长度 
int len(int x){
	if(x<10) return 1;
	return len(x/10)+1;
}
	
// 取x的第k位数字
int f(int x, int k){
	if(len(x)-k==0) return x%10;
	return _____________________;  //填空  f(x/10,k)
}
	
int main()
{
	int x = 23574;
	printf("%d\n", f(x,3));
	return 0;
}

6.希尔伯特曲线

希尔伯特曲线是以下一系列分形曲线 Hn 的极限。我们可以把 Hn 看作一条覆盖 2^n × 2^n 方格矩阵的曲线,曲线上一共有 2^n × 2^n 个顶点(包括左下角起点和右下角终点),恰好覆盖每个方格一次。

Hn(n > 1)可以通过如下方法构造:
1. 将 Hn-1 顺时针旋转90度放在左下角
2. 将 Hn-1 逆时针旋转90度放在右下角
3. 将2个 Hn-1 分别放在左上角和右上角
4. 用3条单位线段把4部分连接起来

对于 Hn 上每一个顶点 p ,我们定义 p 的坐标是它覆盖的小方格在矩阵中的坐标(左下角是(1, 1),右上角是(2^n, 2^n),从左到右是X轴正方向,从下到上是Y轴正方向),
定义 p 的序号是它在曲线上从起点开始数第几个顶点(从1开始计数)。

以下程序对于给定的n(n <= 30)和p点坐标(x, y),输出p点的序号。请仔细阅读分析源码,填写划线部分缺失的内容。

#include <stdio.h>

long long f(int n, int x, int y) {
    if (n == 0) return 1;
    int m = 1 << (n - 1);
    if (x <= m && y <= m) {
        return f(n - 1, y, x);
    }
    if (x > m && y <= m) {
        return 3LL * m * m + f(n - 1, ________________ , m * 2 - x + 1); //  填空 m+1-y
    }
    if (x <= m && y > m) {
        return 1LL * m * m + f(n - 1, x, y - m);
    }
    if (x > m && y > m) {
        return 2LL * m * m + f(n - 1, x - m, y - m);
    }
}

int main() {
	int n, x, y;
    scanf("%d %d %d", &n, &x, &y); 
    printf("%lld", f(n, x, y));

    return 0;
}

7. 快速排序

以下代码可以从数组a[]中找出第k小的元素。


它使用了类似快速排序中的分治算法,期望时间复杂度是O(N)的。
 

#include <stdio.h>

int quick_select(int a[], int l, int r, int k) {
	int p = rand() % (r - l + 1) + l;
	int x = a[p];
	{int t = a[p]; a[p] = a[r]; a[r] = t;}
	int i = l, j = r;
	while(i < j) {
		while(i < j && a[i] < x) i++;
		if(i < j) {
			a[j] = a[i];
			j--;
		}
		while(i < j && a[j] > x) j--;
		if(i < j) {
			a[i] = a[j];
			i++;
		}
	}
	a[i] = x;
	p = i;
	if(i - l + 1 == k) return a[i];
	if(i - l + 1 < k) return quick_select( ____________ ); //填空 a, p, r, k-i+l
	else return quick_select(a, l, i - 1, k);
}
	
int main()
{
	int a[] = {1, 4, 2, 8, 5, 7, 23, 58, 16, 27, 55, 13, 26, 24, 12};
	printf("%d\n", quick_select(a, 0, 14, 5));
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_20799821/article/details/88198029
今日推荐