第二周代码(贪心 + 栈实现fib数列)

2023/10/16        周一

贪心算法

对问题求解时不从整体最优上加以考虑,只做出在某种意义上的局部最优解。通俗来讲,就像你去吃自助餐都会挑最贵的吃,而不考虑所吃的总体营养是否搭配均衡,会不会引发胰腺炎等健康问题。当下的任务就是挑最贵的吃。

最典型案例的就是背包问题

腾讯有这么一个游戏叫暗区突围,成功携带物资从地图撤离是你的最终目标。当你带了一个背包进入对局时,你搜索到了很多杂物,背包装不下了。你应该怎么挑选杂物,让带出的收益最大呢。那当然是挑贵的带!

但是,贵的物资重量和占背包体积都不一样,比如说15000的钢筋剪,占6格空间,20kg重。带上跑不快,容易被人发现被打死(不能超重)。这时候贪心算法就发挥作用了,先按重量排序,算出每件物品一格空间多少钱。这里有两种解法,一是尽可能塞满背包格子,二是不超重,不必塞满格子。

蓝桥杯练习1 删数

【问题描述】

有一个长度为n(n <= 240)的正整数,去掉其中任意s个数字后,将剩余的数保持原来的次序组成一个新的正整数。对给定的n和s,编程寻找一种方案,使得剩下的数字组成的新数最小

【输入格式】
输入两行,正整数n和一个整数s

【输出格式】
一个数字,表示最后剩下的最小数。

【输入样例】

175438

4

【输出样例】

13

【解题思路】

没有使用贪心:

在n中找到最大值,然后删除

使用贪心:

数组中if判断 a[i]>a[i+1],删除 a[i],数字前移

【参考代码】

没有使用贪心:

#include <iostream>
using namespace std;
#include <algorithm>
int arr[20] = { 0 };

void getNumber(int num)//取数,放在数组中
{
	int i = 0;
	while (num)
	{
		int temp;
		temp = num % 10;
		arr[i] = temp;
		num /= 10;
		i++;
	}
}

int deleteNum(int num)
{
	for (int i = 0; sizeof(arr) / sizeof(int); i++)
	{
		if (arr[i] == num)
		{
			arr[i] = 0;
			return 0;
		}
	}
}

int main()
{
	int n, s;
	cin >> n;
	cin >> s;
	getNumber(n);
	//寻找最大值
	for (int i = 0; i < s; i++)
	{
		int max = 0;
		for (int j = 0; j < sizeof(arr) / sizeof(int); j++)
		{
			if (arr[j] > max)
				max = arr[j];
		}
		deleteNum(max);
	}
	//排序后输出
	sort(arr, arr + 20);
	for (int i = 0; i < 20; i++)
	{
		if (arr[i] != 0)
			cout << arr[i];
	}
}

使用贪心:

#include <iostream>
using namespace std;
//使用贪心

int main()
{
	char str[20];
	int s;
	cin >> str;
	cin >> s;
	for (int j = 0; j < s; j++)
		for (int i = 0; i < sizeof(str) / sizeof(char); i++)
		{
			if (str[i] > str[i + 1])
			{
				str[i] = str[i + 1];
			}
		}
	cout << str;
}

简便了很多

【输出结果】

2023/10/17        周二

蓝桥杯练习2 翻硬币

【题目描述】

         小明正在玩“翻硬币”的游戏。桌上放着排成一排的若干硬币。我们用“*”表示正面用“o”表示反面(是小写字母,不是零)
         例如,可能的情形是**oo***oooo  
         如果同时翻转左边的两个硬币,则变为 oooo***ooo0。
         现在的问题是:如果已知初始状态和要达到的目标状态,且每次只能同时翻转相邻的两个硬币,那么对于特定的局面,最少要翻动多少次呢?
         我们约定:把翻动相邻的两个硬币叫作一步操作。
【输入格式】
两行等长的字符串,分别表示初始状态和要达到的目标状态,每行的长度小于 1000。

【输出格式】

一个整数,表示最小操作步数

【样例输入】

*o**o***o***

*o***o**o***

【样例输出】

1

【题目分析】

贪心算法只看局部,局部最优解

两行字符相同就去掉,不同的情况是下面四种

做完啦!

【参考代码】

#include <iostream>
using namespace std;
#include <string>

int main()
{
	char str1[15];
	char str2[15];
	int cnt = 0;
	cin >> str1; 
	cin >> str2;
	//去掉相同项
	for (int i = 0; i < sizeof(str1) / sizeof(char); i++)
	{
		if (str1[i] == str2[i])
		{
			str1[i] = 0;
			str2[i] = 0;
		}
	}
	//查找是否符合情况
	for (int i = 0; i < sizeof(str1) / sizeof(char); i++)
	{
		if ((str1[i] == 'o' && str1[i + 1] == 'o') &&
			(str2[i] == '*' && str2[i + 1] == '*'))
			cnt++;
		if ((str1[i] == 'o' && str1[i + 1] == '*') &&
			(str2[i] == '*' && str2[i + 1] == 'o'))
			cnt++;
		if ((str1[i] == '*' && str1[i + 1] == 'o') &&
			(str2[i] == 'o' && str2[i + 1] == '*'))
			cnt++;
		if ((str1[i] == '*' && str1[i + 1] == '*') &&
			(str2[i] == 'o' && str2[i + 1] == 'o'))
			cnt++;
	}
	cout << cnt;
}

【运行结果】

2023/10/18        周三 

蓝桥杯练习3 分糖果


【题目描述】
有 n个小朋友坐成一圈, 每人有 a[]个糖果。 

每人只能给左右两边的人传递糖果。 
每人每次传递一个糖果的代价为 1。
求使所有人获得均等糖果的最小代价。
【输入格式】
第一行输入一个正整数 n, 表示小朋友的人数。

接下来的 n行, 每行一个整数 a[i], 表示第i个小朋友初始得到的糖果颗数

【输出格式】

输出一个整数,表示最小代价。
【数据范围】
1≤n≤1000000,0<a[i]<2X10 ,数据保证一定有解

【样例输入】

4

1

2

5

4

【样例输出】

4

【题目分析】

利用贪心算法,只考虑相邻两个数的情况。

考虑小朋友是坐成一个圈的,所以a[0]和a[n-1]可以互相交换糖果

【参考代码】

#include <iostream>
using namespace std;

int a[10] = { 0 };

int main()
{
	int n, i;//小朋友个数
	int cnt = 0;
	cin >> n;
	//input
	for (i = 0; i < n; i++)
	{
		cin >> a[i];
	}
	for (i = 0; i < n; i++)
	{//相邻两个数之间进行加减
		if (a[i - 1] < a[i] )
		{
			a[i]--;
			a[i - 1]++;
			cnt++;
		}
		else if (a[i] > a[i + 1] )
		{
			a[i]--;
			a[i + 1]++;
			cnt++;
		}
		//边界(数组头尾)之间的情况
		else if (i == n - 1)
		{
			if (a[i] > a[0])
			{
				a[i]--;
				a[0]++;
				cnt++;
			}
			else
			{
				a[0]--;
				a[i]++;
				cnt++;
			}
		}
	}
	cout << cnt;
}

【运行结果】

4

2023/10/19        周四

斐波那契数列(栈实现)

【代码分析】

先放第一个,第二个进去栈

 取出这两个数,加起来得a3,栈顶元素放a1,a3传给a2,再放进去

 取出这两个数,加起来得a3,栈顶元素放a1,a3传给a2,再放进去(重复步骤)

【参考代码】

主程序

#include <stdio.h>
typedef int Elemtype;
#define MaxSize 5
#include "Stack.h"

int main()
{
	int a1 = 1, a2 = 1, a3;
	int n, i;
	Stack s;
	StackInitiate(&s);
	//输入第n个值的位置
	scanf("%d", &n);

	for(i = 0; i < n - 2; i++)
	{
		push(&s, a1);
		push(&s, a2);
		
		a3 = a1 + a2;
		pop(&s, &a1);
		pop(&s, &a2);
		a2 = a3;
	}
	printf("%d\n", a3);
}

Stack.h文件

//typedef int Elemtype;
typedef struct Stack
{
	Elemtype stack[MaxSize];
	int top;  //栈顶下标值
}Stack;
//栈初始化
void StackInitiate(Stack *S)	
{
	S->top = 0;
}
//返回栈的大小
int StackSize(Stack S)
{
	return S.top;
}
//判断栈是否为空
int isEmpty(Stack S)
{
	if(S.top <= 0) //空栈的情况
		return 0;
	else
		return 1;
}
//清空栈
void ClearStack(Stack *S)
{
	S->top = 0;
}
//入栈
int push(Stack *S, Elemtype x)
{
	if (S->top >= MaxSize)
	{
		printf("栈已满无法插入!\n");
		return 0;
	}
	else
	{
		S->stack[S->top] = x;
		S->top++;
		return 1;
	}
}
//出栈
int pop(Stack *S, Elemtype *d)
{
	if(S->top <= 0)
	{
		printf("栈已空无数据元素出栈!\n");
		return 0;
	}
	else
	{
		S->top--;  //先减后弹出
		*d = S->stack[S->top];  //将栈顶元素值赋给*d
		return 1;
	}
}
//取栈顶元素
int getTopElem(Stack S, Elemtype *d)
{
	if(S.top <= 0)
	{
		printf("栈已空!\n");
		return 0;
	}
	else
	{
		*d = S.stack[S.top - 1];  //将栈顶元素值赋给*d
		return 1;
	}
}

【运行结果】

2023/10/20        周五

蓝桥杯练习4 推销员

【题目描述】
阿明是一名推销员,他奉命到螺丝街推销他们公司的产品。螺丝街是一条死胡同,出口与入口是同一个,街道的一侧是围墙,另一侧是住户。螺丝街一共有N家住户,第i家住户到入口的距离为S_i米。由于同一栋房子里可以有多家住户,所以可能有多家住户与入口的距离相等。阿明会从入口进入,依次向螺丝街的X家住户推销产品,然后再原路走出去。

阿明每走1米就会积累1点疲劳值,向第i家住户推销产品会积累A_i​点疲劳值。阿明是工作狂,他想知道,对于不同的X,在不走多余的路的前提下,他最多可以积累多少点疲劳值。

【输入格式】
第一行有一个正整数N,表示螺丝街住户的数量。

接下来的一行有N个正整数,其中第i个整数S_i表示第i家住户到入口的距离。数据保证S_1≤S_2≤…≤S_n<10^8      

接下来的一行有N个正整数,其中第i个整数A_i表示向第ii户住户推销产品会积累的疲劳值。数据保证A_i<1000。

【输出格式】
输出N行,每行一个正整数,第i行整数表示当X=i时,阿明最多积累的疲劳值。

【样例输入1】

5
1 2 3 4 5
1 2 3 4 5
【样例输出1】 

15
19
22
24
25

【样例输入2】

5
1 2 2 4 5
5 4 3 4 1

【样例输出2】 

12
17
21
24
27

【题目分析】

X=1:向最里面住户5推销,往返走路的疲劳值为5+5,推销的疲劳值为5,总疲劳值为15。

X=2:向前一位住户4推销,推销的疲劳值为4,总疲劳值为19。

X=3:向前一位住户3推销,推销的疲劳值为3,总疲劳值为22。

X=4:向前一位住户2推销,推销的疲劳值为2,总疲劳值为24。

X=5:向前一位住户1推销,推销的疲劳值为1,总疲劳值为25。

走到最后开始,一点一点往前推,往返走路的疲劳值就先算上去。

样例2就不一样了

路口就有5个住户,是不是要先到呢

题目说在不走多余的路的前提下,他最多可以积累多少点疲劳值。

那就往最里面走,而且要是比较多的住户。

【参考代码】

#include <iostream>
using namespace std;

int dis[10] = { 0 };//住户离入口的距离
int house[10] = { 0 };//住户数量

//返回该住户离入口的距离
int searchMaxDistance(int num, int N)
{
	int i;
	for (i = 10; i > 0; i--)
	{
		if (num == house[dis[i]])
			break;
	}
	return dis[i];
}
//贪心算法,去最远最多住户的地方去推销
//只用一次,找远+多的
int maxGreedy(int house[], int N)
{
	int i;
	int max = house[0];
	for (i = N / 2; i < 10; i++)
	{		
		if (house[i] > max)
			max = house[i];
	}
	return max;
}

int max(int house[], int N)
{
	int i;
	int max = house[0];
	for (i = 0; i < 10; i++)
	{
		if (house[i] > max)
			max = house[i];
	}
	return max;
}

int main()
{
	int N;
	cin >> N;
	for (int i = 1; i <= N; i++)
	{
		cin >> dis[i];
		//dis[i] = i;
	}
	for (int i = 1; i <= N; i++)
	{
		cin >> house[i];
		//house[i] = i;
	}
	int temp, d1, d2, res = 0;
	//多的住户
	temp = maxGreedy(house, N);
	//远的距离
	d1 = searchMaxDistance(temp, N);//max的距离
	res = 2 * d1 + temp;
	cout << res << endl;
	house[d1] = 0; dis[d1] = 0;

	temp = max(house, N);
	d2 = searchMaxDistance(temp, N);
	if(d2 > d1)//判断小于d1,小于就不用加距离了
		res += 2 * d2 + temp;
	else
		res += temp;
	cout << res << endl;
	house[d2] = 0; dis[d2] = 0;

	temp = max(house, N);
	d2 = searchMaxDistance(temp, N);
	if (d2 > d1)//判断小于d1,小于就不用加距离了
		res += 2 * d2 + temp;
	else
		res += temp;
	cout << res << endl;
	house[d2] = 0; dis[d2] = 0;

	temp = max(house, N);
	d2 = searchMaxDistance(temp, N);
	if (d2 > d1)//判断小于d1,小于就不用加距离了
		res += 2 * d2 + temp;
	else
		res += temp;
	cout << res << endl;
	house[d2] = 0; dis[d2] = 0;

	temp = max(house, N);
	//cout << temp << endl;
	d2 = searchMaxDistance(temp, N);
	if (d2 > d1)//判断小于d1,小于就不用加距离了
		res += 2 * d2 + temp;
	else
		res += temp;
	cout << res << endl;
	house[d2] = 0; dis[d2] = 0;
}

【运行结果】

 数据结构  数组的应用

1、设矩阵A、矩阵B为n阶对称矩阵,矩阵元素为整数类型,要求:

(1)若A、B采用压缩存储方式,请编写算法实现矩阵乘法运算C=A*B。请注意两个对称矩阵的乘积不一定是对称的。

(2)写一压缩矩阵的元素输出函数,要求按矩阵行列方式输出元素。

(3)以下面的数据为测试例子,编写一个主程序调用以上两个函数进行测试,输出矩阵A,B,C。以下两矩阵分别是矩阵A和矩阵B。

10  20   30

20  40   50

30  50   60

1  2  3

2  4  5

3  5  6

【输出结果】

                            

【代码】

#include <stdio.h>
#include <malloc.h>
//创建
int **get2DArray(int row, int col)
{
	int **a, i;
	a = (int **) calloc(row, sizeof(int *));
	for(i = 0; i < row; i++)
	{
		a[i] = (int *) calloc(col, sizeof(int));
	}
	return a;
}

//void print2DArray(int row, int col,)
//销毁
void destroy2DArray(int **a, int row)
{
	int i;
	for(i = 0; i < row; i++)
	{
		free(a[i]);
	}
}

int main()
{
	int n, i, j, k, row, col;
	int **a1, **a2, **a3;
	int b[6];
	printf("输入阶数\n");
	scanf("%d", &n);//输入阶数
	row = col = n;
	a1 = get2DArray(row, col);
	printf("生成矩阵A,输入压缩矩阵的数\n");
	
	for(i = 0; i < row; i++)
	{
		for(j = 0; j <= i; j++)
		{
			if( i == j )//关键点
				scanf("%d", &a1[i][j]);
			else
			{
				scanf("%d", &a1[i][j]);
				a1[j][i] = a1[i][j];//关键点
			}				
		}		
	}
//	for(i = 0; i < row; i++)
//	{
//		for(j = 0; j < col; j++)
//			scanf("%d", &a1[i][j], &a1[j][i]);
//			a1[j][i] = a1[i][j];
//	}
	//输出矩阵
	for(i = 0; i < row; i++)
	{
		for(j = 0; j < col; j++)		
			printf("\t%d", a1[i][j]);
		printf("\n");
	}

	printf("生成矩阵B,输入压缩矩阵的数\n");
	a2 = get2DArray(row, col);

	for(i = 0; i < row; i++)
	{
		for(j = 0; j <= i; j++)//先填下半
		{
			if( i == j )//关键点
				scanf("%d", &a2[i][j]);
			else
			{
				scanf("%d", &a2[i][j]);
				a2[j][i] = a2[i][j];//关键点
			}				
		}		
	}
	//输出矩阵
	for(i = 0; i < row; i++)
	{
		for(j = 0; j < col; j++)		
			printf("\t%d", a2[i][j]);
		printf("\n");
	}
	printf("\n");
	
	printf("A * B =");
	a3 = get2DArray(row, col);

	for(i = 0; i < row; i++)
	{
		for(j = 0; j < col; j++)
		{
			for(k = 0; k < n; k++)//负责遍历当前位置行和列
			{
				a3[i][j] += a1[i][k] * a2[k][j];
			}
			//a3[i][j] += a1[i][j] * a2[j][i];	
		}
	}
	//输出矩阵
	for(i = 0; i < row; i++)
	{
		for(j = 0; j < col; j++)		
			printf("\t%d", a3[i][j]);
		printf("\n");
	}
}

2023/10/21        周日

蓝桥杯练习5 排座位

【问题描述】
        上课的时候总有一些同学会和前后左右的人交头接耳,这是令班主任十分头疼的一件事情。不过,班主任小雪发现了一些有趣的现象,当同学们的座次确定下来之后,只有有限的 D对同学在上课时会交头接耳。同学们在教室中坐成了 M行 N列,坐在第i行第i列的同学的位置是(i,j),为了方便同学们进出,教室中设置了 K 条横向的通道和 L条纵向的通道。于是,聪明的小雪想到了一个办法,这或许可以减轻上课时学生交头接耳的问题:她打算重新摆放桌椅,改变同学们桌椅之间通道的位置,因为如果一条通道隔开了两个会交头接耳的同学,那么他们就不会交头接耳了。请你帮忙给小雪编写一个程序,给出最好的通道划分方案,在该方案下,上课时交头接耳的学生对数是最少的。

【输入格式】

        输入的第一行有 5 个用空格隔开的整数,分别是M、N、K、L、D。
        接下来的 D行,每行有 4个用空格隔开的整数,第 i行的 4个整数 Xi、Yi、Pi、Qi表示坐在位置(Xi,Yi)与(Pi, Qi)的两个同学会交头接耳(输入保证他们前后或者左右相邻)。

        输入数据保证最优方案的唯一性。

【输出格式】
        输出共两行。
        第一行包含 K 个整数 a1, a2, ..., ak,表示第 a 行和第 ai + 1行之间、第 a2 行和第a2 + 1行之间、···、第 ak 行和第 ak + 1行之间要开辟通道,其中 ai < ai + 1,  每两个整数之间用空格隔开(行尾没有空格)。
        第二行包含 L 个整数 b1, b2, ..., bL,表示第 b1 列和第 b1 + 1列之间、第 b2 列和第b2 + 1列之间、···、第 bL 列和第 bL+1 列之间要开辟通道,其中 bi < bi+1,  每两个整数之间用空格隔开(行尾没有空格)。
【数据范围】
2<N,M<1000,0≤K<M,0<L<N,D<2000。

【样例输入】

4 5 1 2 3

4 2 4 3

2 3 3 3

2 5 2 4

【样例输出】

2

2 4

【题目分析】

数据分析后,就改这几个熊孩子的座位就行。二维数组什么的也不用建了,两个数组输出行和列

【参考代码】

#include <iostream>
using namespace std;

//题目:输入的5个数字,行max:4,列max:5,横向通道:1
//纵向通道:2,总通道:3。

int main()
{
	int res_row[5] = {0}, res_col[5] = {0};
	int i = 0, j = 0, k;
	int rowmax, colmax;	//行,列
	int ver_access, par_access, sum_access;	//垂直,平行通道, 总通道
	cin >> rowmax >> colmax >> par_access >> ver_access >> sum_access;
	int r1, r2, c1, c2;
	for (k = 0; k < sum_access; k++)
	{
		cin >> r1 >> c1 >> r2 >> c2;
		if (r1 == r2 && c1 < c2)//判断行是否相等
		{
			res_col[i] = c1;
			i++;
		}
		else if (r1 == r2 && c1 > c2)//判断行是否相等
		{
			res_col[i] = c2;
			i++;
		}
		if (c1 == c2 && r1 < r2)//判断列是否相等
		{
			res_row[j] = r1;
			j++;
		}
		else if (c1 == c2 && r1 > r2)//判断列是否相等
		{
			res_row[j] = r2;
			j++;
		}
		r1 = 0; r2 = 0; c1 = 0; c2 = 0;
	}
	
	for (i = 0; i < 5; i++)
	{
		if (res_row[i] != 0)
			cout << res_row[i] << " ";
	}
		
	cout << "\n" ;
	for (j = 0; j < 5; j++)
	{
		if (res_col[j] != 0)
			cout << res_col[j] << " ";
	}
		
}

【运行结果】

蓝桥杯练习6 分纸牌

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值