20201207会议要点总结

1.开始写大论文札记,考虑做到及格、良好、优秀各自到什么水平。

2.多思考一点

3.以后会议汇报3点:遇到了什么问题、解决了什么问题、怎么解决的问题

第13周-学习备忘录

日期 星期 时间记录 学习内容 日合计
11.30 1 9:00-11.30
13:00-17:30
19:00-22:30
上位机烧录User问题卡死问题解决
(上位机问题)
书稿撰写
组会
10.5
12.1 2 9:00-11.30
13:00-17:30
19:00-22:30
上位机烧录User问题卡死问题解决
(上位机问题解决,出现投屏无法烧录问题)
书稿撰写
10.5
12.2 3 9:00-11.30
13:00-17:30
19:00-22:30
上位机烧录User问题卡死问题解决
(寻找问题)
书稿撰写
10.5
12.3 4 9:00-11.30
13:00-17:30
上位机烧录User问题卡死问题解决
(寻找问题)
书稿撰写
7
12.4 5 9:00-11.30
13:00-17:30
19:00-22:30
上位机烧录User问题卡死问题解决
(寻找问题)
书稿撰写
10.5
12.5 6 9:00-11.30
13:00-17:30
19:00-22:30
上位机烧录User问题卡死问题解决
(寻找问题)
书稿撰写
10.5
12.6 7 上位机烧录User问题卡死问题解决
(发现O1编译不成功)
周合计时间
周平均时间

第1个B类问题-灌写程序后不出现信息

问题出现的现象

​ 1.使用串口更新更新User程序后,芯片程序继续运行,但没有信息打印出来,关闭串口更新窗口,使用其他串口工具,可以看到调试信息打印出来。并未有规律的复现

​ 2.经王老师使用发现,第一次打开串口更新更新User程序,有信息打印出来,关闭串口更新窗口,重新导入工程,再打开串口更新程序使用出现异常。

​ 3.根据王老师的提示信息,复现串口更新问题现象,第一次使用串口更新可以正常使用,关闭再打开就会出现调试信息不显示的问题。

问题出现的原因

​ 1.由于C#委托函数的特性,两次解除事件绑定会使得委托失效,即使重新绑定事件委托函数依旧不能运行。

问题解决的过程

​ 1.根据王老师提供的思路,既然使用其他串口工具可以打印信息,而串口更新不能,说明绑定的串口被释放,可关闭串口并重新打开,但经实验证明,此方法未能解决该问题,并且会使得绑定速度变慢。后面取消了该方法。(该问题出现2月未解决)

​ 2.2020年11月29号晚,王老师复现了关闭串口更新窗口,重新导入工程,再打开串口更新程序使用出现异常的现象,根据王老师提供的现象,在本机复现现象,经测试,第一遍打开串口更新程序时,程序灌写多少次没有问题,而关闭后再打开,程序即出现现象,关闭主窗体重新打开IDE,程序又可正常运行,定位至串口更新程序关闭事件导致的打印信息不出现问题,排查关闭事件后发现窗体关闭时,委托事件被多次解除绑定导致失效。

问题解决的办法

​ 1.在关闭事件中将多次解绑函数取消并删除其他冗余代码后,程序可正常运行。

20201201会议要点总结

会议主题:大论文开题

1.大论文的围绕基础

2.大论文要实现的大概目标

3.为什么找,为什么没找,有没有结果

算法–分治法之汉诺塔问题

问题描述

​ 汉诺塔问题起源于印度一个古老传说的益智玩具。大梵天创造世界的时候做了三根金刚石柱子,在一根柱子上从下往上按照大小顺序摞着64片黄金圆盘。大梵天命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子上。并且规定,在小圆盘上不能放大圆盘,在三根柱子之间一次只能移动一个圆盘。

​ 例如:从左到右有A、B、C三根柱子,其中A柱子上面有从小叠到大的3个圆盘,现要求将A柱子上的圆盘移到C柱子上去,期间有一个原则:一次只能移到一个盘子且大盘子不能在小盘子上面,求移动的步骤和移动的次数。那么我们可以这样移动,先将最小的盘移动到C柱,然后将中间的盘移动到B柱,再将最小的盘移动到B柱,接着将最大的盘移动到C柱,紧接着将最小的盘移动到A柱,将中间的盘移动到C柱,最后将最小的盘也移动到C柱。这样通过7次移动就可以将三个圆盘从A柱移动到C柱。

问题分析

分析:如果A柱子上面有从小叠到大的n个圆盘,我们需要将问题简化,可以将上面n-1个圆盘看作一个整体M(n-1),下面最大的圆盘看作另一个整体N(1),那么我们就可以将问题简化为下面的形式:通过C柱子作为辅助将上面的整体M全部放到B柱子上,再将整体N从A柱子移动到C柱子上,再通过A柱子作为辅助将整体M全部放到C柱子上,其中A、B、C柱子是相对的,在每次递归中会不断的相对变换。

算法分析

实现汉诺塔算法只需要一个主体函数,函数负责以下三个步骤:

​ 1.利用目标柱为媒介,将上面n-1个圆盘从原始柱暂时移动到辅助柱

​ 2.将原始柱上的最后一个最大的圆盘移动到目标柱上

​ 3.将暂存在辅助柱上的n-1个柱子全部移动到目标柱上

​ Tips:其中1,3两步会不断进行递归,直到只需要移动一个盘子(即n==1)为止,即可实现汉诺塔算法。

代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include <stdlib.h>
#include <cstring>
#include <iostream>

using namespace std;

void Move(char src, char dest)
{
cout << "move " << src << " to " << dest << endl;
}

int Hanoi(int n, char src, char medium, char dest)
{
static int sum = 0;
sum++;
if (n == 1) Move(src, dest);
else
{
//利用目标柱为媒介,将上面n-1个圆盘从原始柱暂时移动到辅助柱
Hanoi(n - 1, src, dest, medium);
//将原始柱上的最后一个最大的圆盘移动到目标柱上
Move(src, dest);
//将暂存在辅助柱上的n-1个柱子全部移动到目标柱上
Hanoi(n - 1, medium, src, dest);
}
return sum;
}

int main()
{
int n;
int a;
cin >> n;
a = Hanoi(n, 'A', 'B', 'C');
cout << a << endl;
return 0;
}

算法–分治法之大整数乘法

问题描述

在计算机上处理一些大数据相乘时,由于计算机硬件的限制,不能直接进行相乘得到想要的结果。可以将一个大的整数乘法分而治之,将大问题变成小问题,变成简单的小数乘法再进行合并,从而解决上述问题。

问题分析

分析:大数据可以分解称高位和地位,比如1534268973可以表示为15342*10^5+68973,那么两个大数据都进行拆解后,可以通过十字相乘获得4个相对较小的乘法,将4个乘法的结果相加即可得到大数据相乘的结果。4个相对较小的乘法各自可以继续分解称4个更小的乘法,再进行合并。

举个例子: 3278×41926

​ =(32×10^2+78)×(419×10^2+26)

​ =32×419×10^4 + 32 × 26 × 10^2 + 78×419×10^2 + 78×26

继续拆分:

​ 32×419×10^4

​ =(3×10+2)×(41×10+9)×10^4

​ =3×41×10^6 + 3×9×10^5 + 2×41×10^5 + 2×9×10^4

​ =123×10^6 + 27×10^5 + 82×10^5 + 18×10^4

​ =13408×10^4

算法实现

算法分析

实现大整数相乘需要三个主体函数,分解函数、乘法函数以及加法函数,分解函数负责将大整数分解成高位和低位,然后乘法函数负责将两个数据的高位和地位十字相乘获得各自的值,加法函数负责将4个相乘的值相加。分解函数需要4个参数——需要分解的大整数src,分解后的相对小的整数的空间des,开始分解的起始位置Start以及分解的长度length。乘法函数同样需要3个参数——两个大整数multiplierA、multiplierB和用来存储结果的数的空间answer。加法函数与乘法函数相同,需要3个参数——两个大整数augend、addend和用来存储结果的数的空间。

代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
#include <stdlib.h>
#include <cstring>
#include <iostream>

using namespace std;

#define M 100
char string_largeInteger_A[1000];
char string_largeInteger_B[1000];

typedef struct _Node
{
int data[M];
int length;
int pow;
}Node, *pNode;

void Multiplie(pNode pa, pNode pb, pNode ans);
void Decompose(pNode src, pNode des, int Start, int length);
void Add(pNode pa, pNode pb, pNode ans);

int main()
{
Node answer, largeInteger_A, largeInteger_B;
int digit;

cout << "输入大整数 a: " << endl;
cin >> string_largeInteger_A;
cout << "输入大整数 b: " << endl;
cin >> string_largeInteger_B;

digit = 0;
largeInteger_A.length = strlen(string_largeInteger_A);
for (int i = largeInteger_A.length - 1; i >= 0; i--)
{
largeInteger_A.data[digit++] = string_largeInteger_A[i] - '0';
}
largeInteger_A.pow = 0;

digit = 0;
largeInteger_B.length = strlen(string_largeInteger_B);
for (int i = largeInteger_B.length - 1; i >= 0; i--)
{
largeInteger_B.data[digit++] = string_largeInteger_B[i] - '0';
}
largeInteger_B.pow = 0;

Multiplie(&largeInteger_A, &largeInteger_B, &answer);
cout << "最终结果是:";
for (int i = answer.length - 1; i >= 0; i--)
cout << answer.data[i];
cout << endl;
return 0;
}

void Multiplie(pNode multiplierA, pNode multiplierB, pNode answer)
{
//【1】定义函数实现所需要的变量
Node multiplierA_highDigit, multiplierA_lowDigit, multiplierB_highDigit, multiplierB_lowDigit;
Node temp_AhBh, temp_AhBl, temp_AlBh, temp_AlBl, temp_answer;
pNode swap_temp;
int bisection_A, bisection_B;
int single_digit, answer_digit, remainder;

//【2】对数据二等分进行预处理,选取二等分点
remainder = 0;
bisection_A = multiplierA->length >> 1;
bisection_B = multiplierB->length >> 1;

//【3】乘法函数的终止条件,当a或b中某个值的基数是个位数的时候,开始直接计算
if (bisection_A == 0 || bisection_B == 0)
{
if (bisection_A == 0)
{
swap_temp = multiplierA;
multiplierA = multiplierB;
multiplierB = swap_temp;
}
answer->pow = multiplierA->pow + multiplierB->pow;

single_digit = multiplierB->data[0];
for (answer_digit = 0; answer_digit < multiplierA->length; answer_digit++)
{
answer->data[answer_digit] = (multiplierA->data[answer_digit] * single_digit + remainder) % 10;
remainder = (multiplierA->data[answer_digit] * single_digit + remainder) / 10;
}
if (remainder) answer->data[answer_digit++] = remainder;
answer->length = answer_digit;
return;
}

//【4】根据二等分点将大整数a拆成高位和低位,大整数b拆成高位和低位
Decompose(multiplierA, &multiplierA_highDigit, bisection_A, multiplierA->length - bisection_A);
Decompose(multiplierA, &multiplierA_lowDigit, 0, bisection_A);
Decompose(multiplierB, &multiplierB_highDigit, bisection_B, multiplierB->length - bisection_B);
Decompose(multiplierB, &multiplierB_lowDigit, 0, bisection_B);

//【5】将大整数a的高位、地位,大整数b的高位、地位进行两两相乘
Multiplie(&multiplierA_highDigit, &multiplierB_highDigit, &temp_AhBh);
Multiplie(&multiplierA_highDigit, &multiplierB_lowDigit, &temp_AhBl);
Multiplie(&multiplierA_lowDigit, &multiplierB_highDigit, &temp_AlBh);
Multiplie(&multiplierA_lowDigit, &multiplierB_lowDigit, &temp_AlBl);

//【6】将十字相乘的四个值相加,获得最终结果
Add(&temp_AlBh, &temp_AlBl, answer);
Add(&temp_AhBl, answer, &temp_answer);
Add(&temp_AhBh, &temp_answer, answer);
}

void Decompose(pNode src, pNode des, int Start, int length)
{
for (int i = Start, j = 0; i < Start + length; i++, j++)
{
des->data[j] = src->data[i];
}
des->length = length;
des->pow = Start + src->pow;
}

void Add(pNode augend, pNode addend, pNode answer)
{
//【1】定义函数实现所需要的变量
pNode swap_temp; //用于被加数和加数的交换的临时变量

int augend_digit, addend_digit, max_digit; //用于记录被加数的位数、加数的位数和两个数中更长的数的位数
int remainder; //用于记录余数实现进位
int augendx_temp, addendx_temp; //被加数按位计算时所用的临时变量加数按位计算时所用的临时变量
int answer_digit; //用于记录结果的位数
int pow_difference; //用于记录被加数与加数次幂之差

//【2】将次幂更小的作为加数,次幂更大的作为被加数以实现统一化的操作,避免分类讨论
if (augend->pow < addend->pow)
{
swap_temp = augend;
augend = addend;
addend = swap_temp;
}

//【3】确定结果的次幂,取次幂更小的加数的次幂作为结果的次幂
answer->pow = addend->pow;

//【4】设置结果的位数为被加数和加数中位数更高的
augend_digit = augend->pow + augend->length;
addend_digit = addend->pow + addend->length;
max_digit = (augend_digit > addend_digit) ? augend_digit : addend_digit ;

pow_difference = augend->pow - addend->pow;
remainder = 0;
for (answer_digit = 0; answer_digit < max_digit - answer->pow; answer_digit++)
{
//【5.1】被加数的次幂高于加数的次幂,所以在次幂差的几位中,被加数都为0; 而当被加数的位数低于加数的位数时,前面不够位数的要补0; 其余按位赋值
if (answer_digit < pow_difference || answer_digit >= augend->length + pow_difference) augendx_temp = 0;
else augendx_temp = augend->data[answer_digit - pow_difference];

//【5.2】加数的次幂更低,不存在次幂差,所以当加数的位数低的时候直接按位赋值,当加数的位数不够位数时要补0
if (answer_digit < addend->length) addendx_temp = addend->data[answer_digit];
else addendx_temp = 0;

//【5.3】被加数、加数和余数按位相加,多出的进位
answer->data[answer_digit] = (augendx_temp + addendx_temp + remainder) % 10;
remainder = (augendx_temp + addendx_temp + remainder) / 10;
}
if (remainder) answer->data[answer_digit++] = remainder;
answer->length = answer_digit;
}

算法–分治法之棋盘覆盖

问题描述

在一个2^k×2^k个方格组成的棋盘中,恰有一个方格与其他方格不同,称该方格为——特殊方格,且称该棋盘为——特殊棋盘。在棋盘覆盖问题中,要用图示的4种不同形态的L型骨牌覆盖给定的特殊棋盘上除特殊方格以外的所有方格,且任何2个L型骨牌不得重叠覆盖。

问题分析

2^k×2^k产生的棋盘中的方格数永远会是3的倍数+1,也就是说该类棋盘一定会被正好填满。对于2^k×2^k棋盘,可以被分成4个2^(k-1)×2^(k-1)棋盘,特殊方格如果出现在左上角,则L型骨牌的方向朝向右下角;如果出现在右上角,则L型骨牌的方向朝向左下角;如果出现在左下角,则L型骨牌的方向朝向右上角;如果出现在右下角,则L型骨牌的方向朝向左上角。L型骨牌放置在四个分支棋盘的交界处。

解题思路

分析:当k>0时,将2^k×2^k分割为4个2^(k-1)×2^(k-1)棋盘。特殊方法必位于4个较小子棋盘之一中,其余3个子棋盘中无特殊方格。为了将这3个无特殊方格的子棋盘转化为特殊棋盘,可以用一个L型骨牌覆盖这3个较小棋盘的会合处,从而将原问题转化为4个较小规模的棋盘覆盖问题。递归地使用这种分割,直至棋盘简化为棋盘1×1

算法实现

每次都对分割后的四个小方块进行判断,判断特殊方格是否在里面。这里的判断方法是每次先记录下整个大方块的左上角方格的行列左边,然后再与特殊方格坐标进行比较,就可以知道特殊方格是否在该块中。如果特殊方块在里面,这直接递归下去求即可,如果不在,这根据分割的四个方块的不同位置,把右下角、左下角、右上角、左上角的方格标记为特殊方块,然后继续递归。在递归函数里,还要有一个变量s来记录边的方格数,每次对方块进行划分时,边的方格数都会减半,这个变量是为了方便判断特殊方格的位置。其次还要有一个变nCount来记录L型骨牌的数量。

算法分析

实现定位需要每个棋盘左上角坐标和边的长度,所以递归函数需要5个参数,特殊方格的横坐标Special_X,纵坐标Special_Y,左上角横坐标Top_Left_X,纵坐标Top_Left_Y,棋盘边的长度Size,以此我们可以制定一个递归函数ChessBoard;

代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int nCount = 0;
int Matrix[100][100];

void ChessBoard(int Top_Left_X, int Top_Left_Y, int Special_X, int Special_Y, int Size);

int main()
{
int Size, Special_X, Special_Y;
memset(Matrix, 0, sizeof(Matrix));
scanf_s("%d", &Size);
scanf_s("%d%d", &Special_X, &Special_Y);
ChessBoard(0, 0, Special_X, Special_Y, Size);

for (int i = 0; i < Size; i++)
{
for (int j = 0; j < Size; j++)
{
printf("%2d ", Matrix[i][j]);
}
printf("\n");
}
}

void ChessBoard(int Top_Left_X, int Top_Left_Y, int Special_X, int Special_Y, int Size)
{
int s; //用于记录棋盘的一半长度
int t; //用于显示L型骨牌的数量

if (1 == Size) return;

s = Size / 2;
t = ++nCount;

//【1】对左上子棋盘的处理
//如果特殊点在左上子棋盘,则不需要另外加点,直接进入下一次递归
if (Special_X < (Top_Left_X + s) && Special_Y < (Top_Left_Y + s))
{
ChessBoard(Top_Left_X, Top_Left_Y, Special_X, Special_Y, s);
}
//如果特殊点不在左上子棋盘,则需要在左上子棋盘的右下角加点,再进入下一层递归
else
{
Matrix[Top_Left_X + s - 1][Top_Left_Y + s - 1] = t;
ChessBoard(Top_Left_X, Top_Left_Y, Top_Left_X + s - 1, Top_Left_Y + s - 1, s);
}

//【2】对右上子棋盘的处理
//如果特殊点在右上子棋盘,则不需要另外加点,直接进入下一次递归
if (Special_X >= (Top_Left_X + s) && Special_Y < (Top_Left_Y + s))
{
ChessBoard(Top_Left_X + s, Top_Left_Y, Special_X, Special_Y, s);
}
//如果特殊点不在右上子棋盘,则需要在右上子棋盘的左下角加点,再进入下一层递归
else
{
Matrix[Top_Left_X + s][Top_Left_Y + s - 1] = t;
ChessBoard(Top_Left_X + s, Top_Left_Y, Top_Left_X + s, Top_Left_Y + s - 1, s);
}

//【3】对左下子棋盘的处理
//如果特殊点在左下子棋盘,则不需要另外加点,直接进入下一次递归
if (Special_X < (Top_Left_X + s) && Special_Y >= (Top_Left_Y + s))
{
ChessBoard(Top_Left_X, Top_Left_Y + s, Special_X, Special_Y, s);
}
//如果特殊点不在左下子棋盘,则需要在左下子棋盘的右上角加点,再进入下一层递归
else
{
Matrix[Top_Left_X + s - 1][Top_Left_Y + s] = t;
ChessBoard(Top_Left_X, Top_Left_Y + s, Top_Left_X + s - 1, Top_Left_Y + s, s);
}

//【4】对右下子棋盘的处理
//如果特殊点在右下子棋盘,则不需要另外加点,直接进入下一次递归
if (Special_X >= (Top_Left_X + s) && Special_Y >= (Top_Left_Y + s))
{
ChessBoard(Top_Left_X + s, Top_Left_Y + s, Special_X, Special_Y, s);
}
//如果特殊点不在右下子棋盘,则需要在右下子棋盘的左上角加点,再进入下一层递归
else
{
Matrix[Top_Left_X + s][Top_Left_Y + s] = t;
ChessBoard(Top_Left_X + s, Top_Left_Y + s, Top_Left_X + s, Top_Left_Y + s, s);
}
}