2023/10/9 周一
队列的应用:杨辉三角
queue.h文件:
//循环队列定义,队首指针和队尾指针
typedef struct
{
ElemType queue[MaxQueueSize];
int front;
int rear;
int count; //计数器
}Queue;
//初始化队列
void QueueInitiate(Queue *Q)
{
Q->count = 0;
Q->front = 0;
Q->rear = 0;
}
//检查队列是否为空
int QueueNotEmpty(Queue Q)
{
if(Q.count == 0)
return 0;
else
return 1;
}
//入队
int QueueAppend(Queue *Q, ElemType x)
{
if ( Q->count>0 && Q->rear == Q->front ) //检查是否申请成功
{
printf("队列已满无法插入!\n");
return 0;
}
else
{
Q->queue[Q->rear] = x;
Q->rear = ( Q->rear + 1 ) % MaxQueueSize;
Q->count++;
return 1;
}
}
//出队
int QueueDelete(Queue *Q, ElemType *x)
{
if (Q->count == 0) //队列中只有一个节点
{
printf("循环队列已空!\n");
return 0;
}
else
{
*x = Q->queue[Q->front];
Q->front = ( Q->front + 1 ) % MaxQueueSize;
Q->count--;
return 1;
}
}
int QueueGet(Queue *Q, ElemType *d)
{
if (Q->count == 0) //队列中只有一个节点
{
printf("循环队列已空!\n");
return 0;
}
else
{
*d = Q->queue[Q->front];
return 1;
}
}
.c文件:
#include <stdio.h>
typedef int ElemType;
#define MaxQueueSize 8 //7的时候队列会满,虽然结果没问题
#include "queue.h"
int main()
{
Queue q1;
QueueInitiate(&q1);
int i, j, x1, x2;
int N = 8;
QueueAppend(&q1, 1); //先将1入队(第一行第一个)
for(i=1; i<N; i++)
{
x2 = 0; //保证每行第一个数是1
for(j=1; j<=i; j++)
{
QueueDelete(&q1, &x1);//出队,元素存在x1地址中
printf("%d ", x1);
QueueAppend(&q1, x1+x2);//入队
x2 = x1;
if(j == i)
QueueAppend( &q1, 1);//每一行最后一个为1
}
printf("\n");
}
}
2023/10/10 周二
农夫过河问题
queue.h文件同上
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 StackNotEmpty(Stack S)
{
if(S.top <= 0) //空栈的情况
return 0;
else
return 1;
}
//清空栈
void ClearStack(Stack *S)
{
S->top = 0;
}
//入栈
int StackPush(Stack *S, ElemType x)
{
if (S->top >= MaxSize)
{
printf("栈已满无法插入!\n");
return 0;
}
else
{
S->stack[S->top] = x;
S->top++;
return 1;
}
}
//出栈
int StackPop(Stack *S, ElemType *d)
{
if(S->top <= 0)
{
printf("栈已空无数据元素出栈!\n");
return 0;
}
else
{
S->top--; //先减后弹出
*d = S->stack[S->top]; //将栈顶元素值赋给*d
return 1;
}
}
//取栈顶元素
int StackTop(Stack S, ElemType *d)
{
if(S.top <= 0)
{
printf("栈已空!\n");
return 0;
}
else
{
*d = S.stack[S.top - 1]; //将栈顶元素值赋给*d
return 1;
}
}
.c文件:
#include <stdio.h>
typedef int ElemType;
#define MaxQueueSize 10
#define MaxSize 15
#include "queue.h"
#include "Stack.h" //栈用于输出
int farmer(int location) //判断农夫位置
{
return (0 != (location & 0x08));
}
int wolf(int location) //判断狼位置
{
return (0 != (location & 0x04));
}
int cabbage(int location) //判断白菜位置
{
return (0 != (location & 0x02));
}
int goat(int location) //判断羊位置
{
return (0 != (location & 0x01));
}
int safe(int location)
{
//羊和白菜被单独留在同一岸边(左右岸都可以)
if( (goat(location) == cabbage(location)) && (goat(location) != farmer(location)) )
return 0; //不安全
//羊和狼被单独留在同一岸边(左右岸都可以)
if( (goat(location) == wolf(location)) && (goat(location) != farmer(location)) )
return 0; //不安全
return 1;
}
void bin_print(int num)
{
char tmp[4];
int i;
for(i=0; i<4; i++)
{
tmp[i] = num & 0x01;
num >>= 1;
}
for(i=3; i>=0; --i)
putchar( (tmp[i] == 0) ? '0' : '1' );
return;
}
int main()
{
int i, movers, location, newlocation;
int rount[16];
for( i=0; i<16; i++)
rount[i] = -1;
Queue moveProcess;
QueueInitiate(&moveProcess);
QueueAppend(&moveProcess, 0x00);
rount[0] = 0;
//异常处理?
while( QueueNotEmpty(moveProcess) && (rount[15] == -1) )
{
QueueGet(&moveProcess, &location); //当前状态
QueueDelete(&moveProcess, &location); //考虑各种物品移动
for(movers = 1; movers <= 8; movers <<= 1 )
{
//<<为左移操作符 左边丢弃一位,右边补0,011->110
//农夫与移动的物品在同一侧
if( (0 != ( location & 0x08 )) == (0 != ( location & movers ) ) )
{
newlocation = location ^ ( 0x08 | movers ); //计算新状态
//新状态安全且未处理
if( safe(newlocation) && ( rount[newlocation] == -1 ) )
{
rount[newlocation] = location; //记录新状态的前驱
QueueAppend(&moveProcess, newlocation); //新状态进入队列
}
}
}
}
printf("rount数组:");
for( i=0; i<16; i++)
printf("%d ", rount[i]);
printf("\n");
if(rount[15] != -1)
{
printf("过河的状态转换步骤为:\n");
Stack s;
StackInitiate(&s);
for( location = 15; location >= 0; location = rount[location] )
{
StackPush(&s, location);//结果放入栈中
if(location == 0) //必要的终止条件
break;
}
i=0;
while(s.top != 0)//top指针判断终止
{
StackPop(&s, &location);
printf("第%d步 ", i);
i++;
bin_print(location);
printf("\n");
}
}
else
printf("No solution.\n");
}
2023/10/11 周三
练习1 组合数
【问题描述】
从4个人中选2个人参加活动,一共有 6种选法。
从n个人中选m个人参加活动,一共有多少种选法?下面的函数实现了这个功能。
请仔细分析代码,填写缺少的部分(下画线部分)。
int f(int n, int m)
{
if(m>n) return 0;
if(m==0) ___;
return f(n-1,m-1) + ____;
}
请仔细阅读分析源码,填写缺失部分的内容。
【题目分析】
在网上找到了这么个公式
按着这个公式写就行
上面一行m==0是用来计算运行到m=0需要几步,这几步其实就是选法
【参考答案】
return 1
f(n-1, m)
2023/10/12 周四
蓝桥杯练习2 李白打酒
【题目描述】
话说大诗人李白,一生好饮。幸好他从不开车。
一天,他提着酒壶,从家里出来,酒壶中有酒2斗。他边走边唱:
无事街上走,提壶去打酒。
逢店加一倍,遇花喝一斗。
这一路上,他一共遇到店5次,遇到花10次,已知最后一次遇到的是花,他正好把酒喝光了。
请你计算李白遇到店和花的次序,可以把遇店记为a,遇花记为b。则:babaabbabbabbbb 就是合理的次序。像这样的答案一共有多少呢?请你计算出所有可能方案的个数(包含题目给出的)。
【题目分析】
一开始想限制酒壶中酒的数量不超过8斗,但是通过这一点做不出什么出来。
方案数,多少种问题用dfs非常好用
【参考代码】
#include <iostream>
using namespace std;
int res;
int dfs(int num, int store, int flower, int flag)
{//不用flag结果为27,flag用于判断最后一步必须是花,酒才能喝完
if (store == 0 && flower == 0 && num == 0 && flag == 0)
{
res++;
return 0;
}
if (store > 0) //遇到店装酒
dfs(num * 2, store - 1, flower, -1);
if (flower > 0 && num > 0) //遇到花喝酒
dfs(num - 1, store, flower - 1, 0);
}
int main()
{
res = 0;
dfs(2, 5, 10, -1);
cout << res;
}
【运行结果】
14
2023/10/13 周五
蓝桥杯练习4 最大公约数
【输入样例】
6 9
【输出样例】
3
【参考代码】
#include <iostream>
using namespace std;
int main()
{
int a, b, temp;
cin >> a >> b;
if (a < b)
{
temp = a;
a = b;
b = temp;
}
while (b != 0)
{
temp = a % b; //temp=0即为已经找到最大公约数,所以b=0为判定条件
a = b;
b = temp;
cout << b << endl;
}
cout << "最大公约数是:" << a;
}
2023/10/14-15 周六日
蓝桥杯练习5 带分数
【题目描述】
100 可以表示为带分数的形式:100=3+69258/714
还可以表示为:100=82+3546/197
注意特征:带分数中,数字 1∼9 分别出现且只出现一次(不包含 0)。
类似这样的带分数,100 有 11 种表示法。
【输入格式】
一个正整数N(N<1000*1000)。
【输出格式】
输出输入数字用数码 1∼9 不重复不遗漏地组成带分数表示的全部种数。
【题目分析】
本题思路和代码参考此大佬推文http://t.csdnimg.cn/elcTu
使用全排列+递归
注意判断条件,因为C++中除法是整除,所以要转化为加减乘来计算
【参考代码】
#include <iostream>
using namespace std;
const int N = 10;
int target; //输入的数
int num[N]; //保存全排列的结果
bool used[N]; //生成全排列过程中标记是否使用过
int cnt; //计数,最后输出的结果
//计算num数组中一段的数是多少
int calc(int l, int r)
{
int res = 0;
for (int i = l; i <= r; i++)
res = res * 10 + num[i];
return res;
}
//生成全排列
//当全排列生成后进行分段
void dfs(int u)
{
//用两层循环分成三段
if (u == 9)
{
for (int i = 0; i < 7; i++)
for (int j = i + 1; j < 8; j++)
{
int a = calc(0, i); //加号左边整数
int b = calc(i + 1, j);
int c = calc(j + 1, 8);
//注意判断条件,因为C++中除法是整除,所以要转化为加减乘来计算
if (a * c + b == c * target)
{
cout << target <<" = " << a << "+" << b << "/" << c << endl;
cnt++;
}
}
return ;
}
//搜索模板
for (int i = 1; i <= 9; i++)
{
if (!used[i])
{
used[i] = true; //标记使用
num[u] = i;
dfs(u + 1);
used[i] = false; //还原现场
}
}
}
int main()
{
cin >> target;
dfs(0);
printf("%d\n", cnt);
return 0;
}
蓝桥杯练习3 组合数
【问题描述】
1~9组成三个3位数,每个数字恰好使用一次,要求3个数的比满足1:2:3,例如192 384 576。
【输入格式】
无数人
【输出格式】
输入T行,每行3个数,表示符合要求的三个三位数。
【样例输出】
192 384 576
...
【题目分析】
按照a:b:c=1:2:3的比例穷举所有数
将a,b,c的百位、十位、个位分别拆分储存到整形数组s[9]中;
判断数组s[9]有无重复数字、是否有数字0
【参考代码】
#include <stdio.h>
int main()
{
int a, b, c; //令三个数分别为a:b:c
int i, j, s[9];
for (a = 100; a < 333; a++) //数值不能重复
{
b = 2 * a, c = 3 * a; //计算b、c的值
s[0] = a / 100; s[1] = a % 100 / 10; s[2] = a % 10; //分离a的百位、十位、个位。下同
s[3] = b / 100; s[4] = b % 100 / 10; s[5] = b % 10;
s[6] = c / 100; s[7] = c % 100 / 10; s[8] = c % 10;
for (i = 0; i < 8; i++) //判断是否有重复数字(前一个数字和后面所有数字比较,如第1个和第2个至9个比较)、是否有数字0
{
for (j = i + 1; j < 9; j++)
if (s[i] == s[j] || s[i] == 0 || s[j] == 0)
break;
if (j < 9) break; //前面break已经终止一个循环,下面break再终止一次
}
if (i == 8 && j == 9) //无重复数字、也无0
printf("%d %d %d\n", a, b, c);
}
return 0;
}
【运行结果】