Fork me on GitHub

新乡市数学建模

新乡市数学建模

活动通知

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
各位同学大家好!
2022年新乡市大学生数学建模联赛即将来临,请同学们认真阅读附件,并积极参加!
参赛对象:全体在校学生
报名时间:5月16日--5月20日
竞赛时间:2022年5月23日上午8:00----2022年5月27日下午20:00
报名及参赛方式:
由参赛队伍在官网报名并在官网中按时提交论文。
论文命名及格式要求以竞赛官网要求为准,请有意参赛的同学把报名表及论文于5月28日中午11:00前交给活动负责人祁孟瑶qq:3308392481
本次竞赛只收集电子版报名信息和论文,不再收集纸质版。
请参赛同学加入QQ群聊:
872816081后续细节将在群内发布
参赛详情见下方文件电子版报名表见附件1
如有问题请联系活动负责人:
马晓雨qq:2205234437
祁孟瑶qq:3308392481

对A题的分析

1
2
3
4
2022322日,中国高等教育学会高校竞赛评估与管理体系研究工作组发布2021全国普通高校大学生竞赛排行榜。进入2017-2021年学科竞赛排行榜榜单的一共有56项竞赛。相比2020年减少了1项竞赛。当前有不少研究探讨了学科竞赛在专业建设中的作用,但针对某一高校学科竞赛分级分类体系的构建研究较少.主要原因来源于两个方面:一方面是学校对比赛的重视程度不同,另一方面是学校和学科的性质不同。这两方面的原因直接决定了学校或者学科参与竞赛和对竞赛分级体系构建的不一样。经过前期调研发现,部分学科竞赛片面追求大辐射范围,有个别学科每年学生参加的竞赛种类有好几十个,很多竞赛管理不规范,信息的不对称也使高校对众多竞赛实际质量缺乏充分的了解,很多比赛变成用时间和金钱换取证书,完全背离了初衷。一些大学一直高度重视学生综合素质的全面发展和创新能力的培养,积极组织学生参与各类学科竞赛,并取得了不错的成绩,但也面临高质量竞赛选择的困惑。
本题目学生需要做的是:选取一个学科(物理、化学、数学、计算机等)的主要赛事,深入研究国家级和省级学科竞赛的主办单位、国际国内影响力和知名度、参与高校层次、参与学生覆盖面、竞赛设奖情况、对学生能力培养的支撑度、竞赛组织的稳定性和延续性等因素。(1)建立数学模型,对竞赛进行科学评价的指标体系进行分类和筛选。
2)对比中国高等教育学会高校竞赛评估与管理体系研究工作组发布的全国普通高校大学生竞赛排行榜,给出相关科学竞赛的排行榜。
3)根据你的模型,对高等教育学会高校竞赛评估与管理体系研究工作组发布的56项竞赛进行排名。

分析:

  • 是一个评价问题
  • 数据需要自己找(自己找数据就会遇到很多问题)

建议放弃

对B题的分析

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
第八届新乡市数学建模竞赛题目
B题 矿石加工质量控制问题
提高矿石加工质量,可以直接或间接地节约不可再生的矿物资源以及加工所需的能源,从而推动节能减排,助力“双碳”目标的实现。矿石加工是一个复杂的过程,在加工过程中,电压、水压、温度作为影响矿石加工的重要因素,直接影响着矿石产品的质量。矿石加工过程如图1所示。某生产车间对于一批原矿进行加工,相关的原矿参数见附件1和附件2。为了方便描述,假设矿石加工过程需要经过系统I和系统II两个环节,两个环节不分先后,其他条件(电压、水压等)保持不变。生产技术人员可以通过传入调温指令,调节温度来改变产品质量。其中系统I和II的温度数据见附件1和附件2。矿石加工过程为2小时整(即:在调节温度2个小时后,可检测得到该调节温度所对应的矿石产品质量的评价指标(A,B,C,D)),假设每次温度调节之后的2个小时内不会传入新的调温指令,附件1和附件2中的温度数据记录了系统的实时温度,调温指令下达后系统温度基本与调温指令设定的温度相同,但是有轻微波动。注:附件1和附件2中,原矿参数和过程数据未给出数据的具体名称,不同类型的数据,采集时间间隔不同。


1 矿石加工过程
问题1:附件1给出了该生产车间2022-01-132022-01-22的生产加工数据,请应用附件1的数据,建立数学模型,给出利用系统温度预测产品质量的方法。在给定的2022-01-23原矿参数(见附件1)和系统设定温度(见表1,假设系统温度与调温指令设定的温度相同)下,给出产品质量预测结果。注意:在所给数据中,由于其他不确定因素的影响,在相同(或者相近)的系统温度下生产出来的产品质量可能有比较大的差别,在这种情况下请预测可能性最大的产品指标,并填入表1
1 问题1结果
时间 系统I设定温度 系统II设定温度 指标A 指标B 指标C 指标D
2022-01-23 1404.89 859.77
2022-01-23 1151.75 859.77
问题2:根据问题1的结果,利用附件1的数据,假设原矿参数和产品目标质量已知(系统温度未知),请建立数学模型,估计产品目标质量所对应的系统温度。在给定的2022-01-24原矿参数(见附件1)和目标产品质量(见表2)下,给出系统设定温度(假设调温指令设定的温度与系统温度相同)。注意,同一组产品质量可能有多种调温方法都可以得到,请给出可能性最大的系统设定温度,并填入表2
2 问题2结果
时间 指标A 指标B 指标C 指标D 系统I设定温度 系统II设定温度
2022-01-24 79.17 22.72 10.51 17.05
2022-01-24 80.10 23.34 11.03 13.29

问题3:过程数据是在矿石加工过程中检测得到的(见图1),可以反映原矿质量。由于同一批次(天)的原矿质量有差别,也可能造成在传入相同(或者相近)调温指令后生产出来的产品质量有差别。附件2给出了该生产车间2022-01-252022-04-07的生产加工数据及过程数据。表3给出了矿石产品的销售条件,满足销售条件的产品视为合格产品,否则视为不合格产品,假设每单位时间生产的产品数量相同,合格率=合格产品数/产品总数。请建立数学模型,给出指定系统设定温度,预测矿石产品合格率的方法。在给定的2022-04-08和2022-04-09原矿参数、过程数据(见附件2)和系统设定温度(见表4,假设系统温度与调温指令设定的温度相同)下,给出合格率预测结果,填入表4,并建立数学模型对给出的合格率的准确性进行评价。
3 产品销售条件
指标 指标A 指标B 指标C 指标D
销售条件 77.78 - 80.33 <24.15 <17.15 <15.62
4 问题3结果
时间 系统I设定温度 系统II设定温度 合格率
2022-04-08 341.40 665.04
2022-04-09 1010.32 874.47

问题4:根据问题3中的结果,利用附件2的数据,建立数学模型分析在指定合格率的条件下,如何设定系统温度的方法,并完成以下任务:(1)适当的敏感性分析;(2)对结果准确性的分析;(3)判断能否达到表5中给出的2022-04-102022-04-11产品的合格率要求(原矿参数和过程数据见附件2),如果可以达到,给出系统设定温度(假设系统温度与调温指令设定的温度相同),并将结果填入表5
5 问题4结果
时间 合格率 能否达到 系统I设定温度 系统II设定温度
2022-04-10 80%
2022-04-11 99%


分析

  • 初步判断是一个预测问题
  • 可以采用灰度预测
  • 数据已经给出
  • 关于矿石冲洗的问题

可以试一试

对C题分分析

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
第八届新乡市数学建模竞赛题目
C题 火灾报警系统问题
二十世纪90年代以来,我国火灾探测报警产业化发展非常迅猛,从事火灾探测报警产品生产的企业已超过100家,年产值达几十亿元,已经成为我国高新技术产业的一个组成部分,国外产品也大量进入我国市场。我国每年建筑中新安装的火灾探测器约200万只。
火灾探测器的功能就是捕捉特定的火灾信号,将其转换为电信号传输至火灾报警控制器依据报警算法进行判定,当探测到的信号数值或者变化特征超过阈值时即被判定为火灾。因此探测器的灵敏度决定了对火灾特征响应的灵敏程度,但较高的灵敏度会导致报警可靠性的降低,而较高的可靠性则需要牺牲探测器的灵敏度。因此,探测器的灵敏度和可靠性成为探测器需要平衡考虑的关键参数 (有关火灾报警系统的其他相关背景资料见附件4:火灾报警系统背景资料)。
1为全国2021年各月份的火灾次数及变化趋势,假设我国某城市一年内的火灾起数的变化趋势与全国2021年各月份的火灾次数及变化趋势相似,该城市在(61日至618日)18天内共接到257179条火灾报警系统的报警信息(其中包含误动作所导致的误报警),附件1是该城市61日至618日统计的火灾报警数据;该城市共有18个消防大队,管辖面积如表1所示;除了误动作以外,该城市中还有一部分火灾报警系统存在故障问题如附件2所示。假设正常工作的火灾探测器检测到火灾时一定会报警,忽略时间的影响,当某一建筑内多个火灾探测器的机号与回路编号相同时且这些探测器均发出火灾报警信号,则认为是同一起火灾事故。


1 2021年全国各月份火灾起数(左)和亡人数量(右)

1 各消防大队管辖面积
大队名称 管辖面积(平方公里)
A大队 1712
B大队 692
C大队 1100
D大队 1631
E大队 412
F大队 1524
G大队 122
H大队 532
I大队 96
J大队 58
K大队 1831
L大队 1561
M大队 1997
N大队 246
O大队 483
P大队 24
Q大队 2151
R大队 13
在探测器安装得当,符合标准的假设下,讨论如下问题:
问题1:请根据文中叙述及附件1,确定该城市61日至618日的真实火灾起数,并查阅参考文献,结合附件2、图1(附件2中部分部件无需分析,请依据附件1的部件名称先对附件2的部件进行模型筛选),通过建立模型对附件1中的各类型部件进行分析,利用可靠性和故障率对各类型部件进行评价,帮助政府选取更加可靠的火灾探测器类型。
问题2:通过阅读参考文献,结合问题1得到的数据结论,选择合适参数建立区域报警部件类型智能研判模型,当某大队辖区内某类型部件发出报警信息时,能够较好判断是否属于误报,提高报警准确率,并对附件3中各大队不同部件发出的报警信号进行真实性评价,确定附件3中各报警信号是真实火灾的概率。
问题3:根据问题1所获得的各辖区火灾数据以及问题2的结果,结合表1分析该市各消防大队的综合管理水平,并将综合管理水平最低的三个辖区的技术指标(如辖区火灾发生频率、部件故障率、部件可靠性等)进行量化,提出改进方案。
问题4:根据有关文献和问题1至问题3模型分析的结果,请有针对的提出火灾报警系统各部件管理维护的意见建议。

问题分析

  • 评价类问题
  • 有数据
  • 够搞头

对D题的分析

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
第八届新乡市数学建模竞赛题目
D题 血管机器人的订购与生物学习
随着微机电系统的发展,人类已经可以加工越来越小的机器。这些机器小到一定程度就可以放进血管开展疾病治疗,这就是血管机器人。血管机器人可以携带药物放入血管里定点治疗与血管有关的疾病,还可以充当血管清道夫,清除病毒,保持人体健康。因而,血管机器人越来越受到人们的关注。
血管机器人有多种类型,其中某医院使用的是ABLVR型号的血管机器人。这种血管机器人有两大特点:①可以组装。机器人有一个容器艇(类似于潜艇),有动力,可在血液中游动。容器艇四周安装了4个操作手,操作手类似于人,有生物大脑和机械臂,生物大脑控制着机械臂进行工作。操作手可以从容器艇上拆卸、安装、更换。②需要学习。这种血管机器人没有直接的信息复制功能,新购买的操作手在工作之前需要提前进行生物学习(训练),类似于人脑学习,需要在特定的环境中由已经学习好的操作手(熟练工)“指导”若干个生物大脑芯片空白的操作手(新手)在仿真血管中进行学习,直到“新手”能够达到“熟练工”的水平为止,时间为一周。
血管机器人在患者血管中工作时间是一周,一周后必须取出。取出后操作手拆卸下来需要进行一周的保养才能再次开展工作,如没有安排工作,则一直需要保养。新购买的容器艇需要经过一周的检查调试后才可以投入使用,使用结束后容器艇并不必须要保养,可以连续使用,但如果不使用也需要保养。假定购买的容器艇和操作手在每周开始时到货并立即安排检查调试和生物学习(训练)。相关成本数据见附件1。附件2是第1-104周该医院所需要的血管机器人数量。
该医院从第1周开始开展血管机器人治疗业务,并假定开始前已经有了13个容器艇和50个熟练操作手。请建立数学模型,回答下列问题。
问题1:在每周开始时,医院可以购买到操作手和容器艇。每个熟练操作手可以作为指导者“指导”10个购买的新操作手进行生物学习。如果仅仅考虑第1-8周,请问每周需要购买多少容器艇和操作手,既满足治疗又能够使运营成本达到最低?
问题2:血管机器人在患者血管中工作有风险,一旦碰上巨噬细胞,如果躲避不及,将会完全损毁。假设每周有20%的血管机器人损毁(损毁的个数按四舍五入取整),其他条件遵循问题1,通盘考虑第1-104周,请问总共需要购买多少容器艇和操作手,既满足治疗又能够使运营成本达到最低?并将相关结果填入表1。另外,将第1-8周的结果数据与问题1的第1-8周的结果数据进行对比分析。
1:问题2相关结果数据
周次 购买的容器艇数量 购买的操作手数量 保养的操作手数量 保养的容器艇数量 参与训练的操作手数量(含“熟练工”和“新手”) 总成本
(单位:元)
12
26
52
78
101
102
103
104
1-104周(总计)
问题3:如果每名熟练操作手可以“指导”新操作手的数量调整为不超过20个,假设每周有10%的血管机器人损毁(损毁的个数按四舍五入取整),同问题2,请研究第1-104周里总共需要购买多少容器艇和操作手既满足治疗又能够使运营成本达到最低?将相关结果数据填入表2
2:问题3的相关结果数据
周次 购买的容器艇数量 购买的操作手数量 保养的操作手数量 保养的容器艇数量 参与训练的操作手数量(含“熟练工”和“新手”) 总成本
(单位:元)
12
26
52
78
101
102
103
104
1-104周(总计)
问题4:如果购买操作手和容器艇有优惠政策,即容器艇一次性购买量不超过5个时的单价为200元/个;容器艇一次性购买量超过5个但不超过10个时,超过5个的那部分单价为180元/个;容器艇一次性购买量超过10个时,超过10个的那部分单价为160元/个。同样,操作手一次性购买量不超过20个时的单价为100元/个;操作手一次性购买量超过20个但不超过40个时,超过20个的那部分单价为90元/个;操作手一次性购买量超过40个时,超过40个的那部分单价为80元/个。其他条件遵循问题3,则第1-104周里总共购买的容器艇和操作手将如何调整?将相关结果数据填入表3
3:问题4的相关结果数据
周次 购买的容器艇数量 购买的操作手数量 保养的操作手数量 保养的容器艇数量 参与训练的操作手数量(含“熟练工”和“新手”) 总成本
(单位:元)
12
26
52
78
101
102
103
104
1-104
(总计)
问题5:预测第105-112周的血管机器人的使用需求。为了研究第105-112周的血管机器人的使用成本,在遵循问题4条件的基础上,有两种方案可以考虑。
方案1:在第1-104周最优结果的基础上,医院在第105周开始时有可能需要以每个300元的高价购买能够直接使用的容器艇和每个150元购买熟练操作手,而后续每周均按问题4中的优惠政策购买合适数量的新容器艇和新操作手,满足第105-112周的血管机器人的需求。
方案2:通盘考虑第1-112周的血管机器人的需求。
请比较两种方案的第1-112周最低运营成本的差额。

附件1 血管机器人相关成本
类别 价格(成本)
容器艇 200元/个
操作手 100元/个
操作手保养 5元/个/周
容器艇保养 10元/个/周
操作手(含“熟练工”)训练 10元/个
附件21-104周血管机器人使用数量(单位:个)
1-811 5 4 7 16 6 5 7
9-1613 6 5 7 12 5 4 6
17-249 5 5 11 29 21 17 20
25-3227 13 9 10 16 6 5 7
33-4011 5 5 6 12 7 7 10
41-4815 10 9 11 15 10 10 16
49-5626 21 23 36 50 45 45 49
57-6457 43 40 44 52 43 42 45
65-7252 41 39 41 48 35 34 35
73-8042 34 36 43 55 48 54 65
81-8880 70 74 85 101 89 88 90
89-96100 87 88 89 104 89 89 90
97-104106 96 94 99 109 99 96 102

问题分析

  • 规划类问题
  • 有数据
  • 如果会使用Lingo会大大加快编写进度
  • 每一问都是前一问的基础上添加新的限制条件

最终选择

写C题

艺术生的填报规则分析

艺术生的填报规则分析

河南2021艺术类高校(或专业)志愿填报和录取有关规定-河南省阳光高考 (haedu.cn)

根据上述这个网站的红头文件,我对河南省的艺术生报名做出如下分析。

报名要求

**专业省统考成绩合格并参加全国普通高等学校招生文化课统一考试且成绩达到相应分数线的考生可按艺术类填报志愿。 **

河南省专业省统考成绩:

  • 美术类 180分;
  • 编导制作类 115分;
  • 书法类 190分;
  • 艺术舞蹈 140分;
  • 国际标准舞 140分;

各种艺术类专业的总分

艺术类专业招生分为美术类(总分300分)

音乐类(分声乐和器乐,考生任选其一,总分200分)、

播音与主持类(总分400分)、

编导制作类(总分200分)、

书法类(总分300分)、

舞蹈类(分艺术舞蹈和国际标准舞,考生任选其一,总分200分

**表演类(总分200分 **

数据来源: 2022年河南省统考分数线公布_腾讯新闻 (qq.com)

高考成绩分档:

要专业成绩和文化课成绩双双过线才能报考某个段的学校

21年成绩1653124042280.png

报名时间

报名时间

对分段的分析

理论来源: 艺术类本科批A段和B段的区别 有什么不同_高三网 (gaosan.com)

**本A段是一本和二本,这类大学是公办学校,有国家重点,也有地方重点,有不少学校相关专业实力都不错,本B段是原来的三本,独立学院、民办院校和中外合作办学专业,学费也比较高。 **

要专业成绩和文化课成绩双双过线才能报考某个段的学校

itext生成pdf

itext生成pdf

最近写了一个java后端生成pdf程序,因此我在这里提供自己生成pdf的一个策略。

使用itext生成pdf

iText的依赖

1
2
3
4
5
6
7
8
9
10
11
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itextpdf</artifactId>
<version>5.5.6</version>
</dependency>

<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itext-asian</artifactId>
<version>5.2.0</version>
</dependency>

这两程序是都需要的,特别是第二个依赖,是itext能够使用字体的重要的依赖

代码实践

学习参考

iText中文帮助文档 - 豆丁网 (docin.com)

生成pdf的代码

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
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
package com.dwx.utils;

import com.dwx.pojo.g_hld1;
import com.dwx.pojo.g_hld2;
import com.itextpdf.text.*;
import com.itextpdf.text.Font;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.pdf.*;

import javax.swing.*;
import java.awt.*;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.Map;

//这是一个生成pdf的工具类
public class pdfUtils {

public Map<String,Object> setPDF(String E,String I,String S,String N,String TT,String F,String J,String P,String csrul,String personalityProfile,String personalityDescription,String field,String careerStudent,String career) throws Exception{

ByteArrayOutputStream stream = new ByteArrayOutputStream();
//创建一个新的文档
//创建一个空的文档并且设置文档的大小
Document document = new Document(PageSize.A4);

PdfWriter.getInstance(document, stream);


//打开文档 准备添加数据
document.open();

//添加数据
//创建字体 基本字体 字体需要不同定制都是以这个基础字体为基础的
BaseFont baseFont = BaseFont.createFont("STSongStd-Light", "UniGB-UCS2-H", BaseFont.EMBEDDED);
//固定格式部分
//主标题
String T = "MBTI职业性格测试报告";
Paragraph Title = new Paragraph();
Title.setFont(new Font(baseFont,23,0));
//居中
Title.setAlignment(Element.ALIGN_CENTER);
Title.add(T);

Title.setSpacingAfter(25);
Title.setSpacingBefore(25);

//副标题
String t = "你的性格类型是:"+csrul;
Paragraph title = new Paragraph();
title.setFont(new Font(baseFont,12,0));
//居中
title.setAlignment(Element.ALIGN_CENTER);
title.add(t);
title.setSpacingAfter(10);
title.setSpacingBefore(0);

//添加百分比部分
String TT1 = E+"% 外向(E) ---- 内向(I) "+I+"%";
String TT2 = S+"% 感觉(S) ---- 直觉(N) "+N+"%";
String TT3 = TT+"% 思考(T) ---- 感情(F) "+F+"%";
String TT4 = J+"% 判断(J) ---- 知觉(P) "+P+"%";

Paragraph tt1 = new Paragraph();
tt1.setFont(new Font(baseFont,10,0));
tt1.add(TT1);
tt1.setAlignment(Element.ALIGN_CENTER);
Paragraph tt2 = new Paragraph();
tt2.setFont(new Font(baseFont,10,0));
tt2.add(TT2);
tt2.setAlignment(Element.ALIGN_CENTER);
Paragraph tt3 = new Paragraph();
tt3.setFont(new Font(baseFont,10,0));
tt3.add(TT3);
tt3.setAlignment(Element.ALIGN_CENTER);
Paragraph tt4 = new Paragraph();
tt4.setFont(new Font(baseFont,10,0));
tt4.add(TT4);
tt4.setAlignment(Element.ALIGN_CENTER);




//第一部分
String t1 = "一、性格特点";
Paragraph T1 = new Paragraph();
T1.setFont(new Font(baseFont,15,0));
T1.add(t1);
T1.setSpacingAfter(10);
T1.setSpacingBefore(10);

//第二部分

String t2 = "1.概要";
Paragraph T2 = new Paragraph();
T2.setFont(new Font(baseFont,13,0));
T2.add(t2);
T2.setSpacingAfter(10);
T2.setSpacingBefore(10);

//第三部分
String t3 = "2.描述";
Paragraph T3 = new Paragraph();
T3.setFont(new Font(baseFont,13,0));
T3.add(t3);
T3.setSpacingAfter(10);
T3.setSpacingBefore(10);

//第四部分
String t4 = "二、适合领域";
Paragraph T4 = new Paragraph();
T4.setFont(new Font(baseFont,15,0));
T4.add(t4);
T4.setSpacingAfter(10);
T4.setSpacingBefore(10);

String t45 = "三、适合职业";
Paragraph T45 = new Paragraph();
T45.setFont(new Font(baseFont,15,0));
T45.add(t45);
T45.setSpacingAfter(10);
T45.setSpacingBefore(10);


//第五部分
String t5 = "1.学生";
Paragraph T5 = new Paragraph();
T5.setFont(new Font(baseFont,13,0));
T5.add(t5);

T5.setSpacingAfter(10);
T5.setSpacingBefore(10);

//第六部分
String t6 = "2.职场";
Paragraph T6 = new Paragraph();
T6.setFont(new Font(baseFont,13,0));
T6.add(t6);

T6.setSpacingAfter(10);
T6.setSpacingBefore(10);


//第七部分
String t7 = "四、用户须知";
Paragraph T7 = new Paragraph();
T7.setFont(new Font(baseFont,15,0));
T7.add(t7);

T7.setSpacingAfter(10);
T7.setSpacingBefore(10);


//第八部分
String p6 = "《性格分析报告》展示的是你的性格倾向,而不是你的知识、技能、经验。\n" +
"MBTI提供的性格类型描述仅供测试者确定自己的性格类型之用,性格类型没有好坏,只有不同。每一种性格特征都有其价值和优点,也有缺点和需要注意的地方。清楚地了解自己的性格优劣势,有利于更好地发挥自己的特长,而尽可能的在为人处事中避免自己性格中的劣势,更好地和他人相处,更好地作重要的决策。\n" +
"";
Paragraph P6 = new Paragraph();
P6.setFont(new Font(baseFont,10,0));
P6.add(p6);
P6.setLeading(15.5f);

//尾缀一
String l1 = "[性格无好坏,人生各不同]";
Paragraph L1 = new Paragraph();
L1.setFont(new Font(baseFont,10,0));
L1.setSpacingBefore(50);
//设置居中
L1.setAlignment(Element.ALIGN_RIGHT);
L1.add(l1);
//尾缀二
String l2 = "留心智愿";
Paragraph L2 = new Paragraph();
L2.setFont(new Font(baseFont,10,0));
//设置居中
L2.setAlignment(Element.ALIGN_RIGHT);
L2.add(l2);
//最后的时间

DateTimeFormatter dtf = DateTimeFormatter.ofPattern("uuuu/MM/dd");
LocalDate localDate = LocalDate.now();
int year = localDate.getYear();
int monthValue = localDate.getMonthValue();
int dayOfMonth = localDate.getDayOfMonth();
System.out.println(year);
System.out.println(monthValue );
System.out.println(dayOfMonth);

String data = year+"年"+monthValue+"月"+dayOfMonth+"日";
Paragraph Data = new Paragraph();
Data.setAlignment(Element.ALIGN_RIGHT);
Data.setFont(new Font(baseFont,10,0));
Data.add(data);



//五个移动的数据
String p1 = personalityProfile;
String p2 = personalityDescription;
String p3 = field;
String p4 = careerStudent;
String p5 = career;

Paragraph P1 = new Paragraph();
P1.setFont(new Font(baseFont,10,0));
P1.add(p1);

Paragraph P2 = new Paragraph();
P2.setFont(new Font(baseFont,10,0));
P2.add(p2);

Paragraph P3 = new Paragraph();
P3.setFont(new Font(baseFont,10,0));
P3.add(p3);

Paragraph P4 = new Paragraph();
P4.setFont(new Font(baseFont,10,0));
P4.add(p4);

Paragraph P5 = new Paragraph();
P5.setFont(new Font(baseFont,10,0));
P5.add(p5);




//将元素添加进去
document.add(Title);
document.add(title);
document.add(tt1);
document.add(tt2);
document.add(tt3);
document.add(tt4);
document.add(T1);
document.add(T2);
document.add(P1);
document.add(T3);
document.add(P2);
document.add(T4);
document.add(P3);
document.add(T45);
document.add(T5);
document.add(P4);
document.add(T6);
document.add(P5);
document.add(T7);
document.add(P6);
document.add(L1);
document.add(L2);
document.add(Data);




//关闭文档
document.close();

Map<String, Object> map = new HashMap<>();

map.put("document",document);
map.put("stream",stream);
return map;
}


public Map<String,Object> setHldPDF(String R, String C, String E, String S, String A, String I, String d1, String d2, String d3, g_hld1 n1, g_hld1 n2, g_hld1 n3, g_hld2 d) throws Exception {
ByteArrayOutputStream stream = new ByteArrayOutputStream();
//创建一个新的文档
//创建一个空的文档并且设置文档的大小
Document document = new Document(PageSize.A4);

PdfWriter.getInstance(document, stream);


//打开文档 准备添加数据
document.open();

//添加数据
//创建字体 基本字体 字体需要不同定制都是以这个基础字体为基础的
BaseFont baseFont = BaseFont.createFont("STSongStd-Light", "UniGB-UCS2-H", BaseFont.EMBEDDED);

//创建标题
String title = "霍兰德职业兴趣测试\n"+"深度分析报告";
Paragraph Title = new Paragraph();
Title.setFont(new Font(baseFont,20,0));
//设置居中
Title.setAlignment(Element.ALIGN_CENTER);
Title.setLeading((float) (15.5f*1.5));
Title.add(title);
Title.setSpacingAfter(20);

//创建文档中固定的部分
String t1 = "测试结果 "+d.getAll_type();
Paragraph T1 = new Paragraph();
T1.setFont(new Font(baseFont,15));
T1.add(t1);
T1.setSpacingBefore(10);
T1.setSpacingAfter(10);

String t2 = "维度分析";
Paragraph T2 = new Paragraph();
T2.setFont(new Font(baseFont,15));
T2.add(t2);
T2.setAlignment(Element.ALIGN_CENTER);
T2.setSpacingBefore(10);
T2.setSpacingAfter(10);


String t3 = "职业匹配";
Paragraph T3 = new Paragraph();
T3.setFont(new Font(baseFont,15));
//设置居中
T3.setAlignment(Element.ALIGN_CENTER);
T3.add(t3);
T3.setSpacingBefore(10);
T3.setSpacingAfter(10);

//设置可以活动的部分
String p6 = d.getAll_career();
Paragraph P6 = new Paragraph();
P6.setFont(new Font(baseFont,10));
P6.add(p6);

String p1 = "现实型R ---- "+R+"%"+"\n"
+"传统型C ---- "+C+"%"+"\n"
+"企业型E ---- "+E+"%"+"\n"
+"社会型S ---- "+S+"%"+"\n"
+"艺术型A ---- "+A+"%"+"\n"
+"研究型I ---- "+I+"%"+"\n";
Paragraph P1 = new Paragraph();
P1.setFont(new Font(baseFont,13));
P1.add(p1);
P1.setAlignment(Element.ALIGN_CENTER);
P1.setLeading((float) (15.5f*1.5));

P1.setSpacingBefore(10);
P1.setSpacingAfter(10);

String t4 = d1;
switch (t4){
case "R现实型": t4 = "R";break;
case "C": t4 = "C";break;
case "E": t4 = "E";break;
case "S": t4 = "S";break;
case "A": t4 = "A";break;
case "I": t4 = "I";break;
default:break;
}
Paragraph T4 = new Paragraph();
T4.add(t4);
T4.setFont(new Font(baseFont,15));
String p3 = n1.getPersonality()+"\n"+"\n"+n1.getCareer();
Paragraph P3 = new Paragraph();
P3.setFont(new Font(baseFont,10));
P3.add(p3);
P3.setSpacingAfter(10);
P3.setSpacingBefore(10);


String t5 = d2;
switch (t5){
case "R现实型": t4 = "R"+"现实性";break;
case "C": t4 = "C";break;
case "E": t4 = "E";break;
case "S": t4 = "S";break;
case "A": t4 = "A";break;
case "I": t4 = "I";break;
default:break;
}
Paragraph T5 = new Paragraph();
T5.add(t5);
T5.setFont(new Font(baseFont,15));
String p4 = n2.getPersonality()+"\n"+"\n"+n2.getCareer();
Paragraph P4 = new Paragraph();
P4.setFont(new Font(baseFont,10));
P4.add(p4);
P4.setSpacingAfter(10);
P4.setSpacingBefore(10);


String t6 = d3;
switch (t6){
case "R现实型": t4 = "R"+"现实性";break;
case "C": t4 = "C";break;
case "E": t4 = "E";break;
case "S": t4 = "S";break;
case "A": t4 = "A";break;
case "I": t4 = "I";break;
default:break;
}
Paragraph T6 = new Paragraph();
T6.add(t6);
T6.setFont(new Font(baseFont,15));


String p5 = n3.getPersonality()+"\n"+"\n"+n3.getCareer();
Paragraph P5 = new Paragraph();
P5.setFont(new Font(baseFont,10));
P5.add(p5);
P5.setSpacingAfter(10);
P5.setSpacingBefore(10);


//尾缀一
String l1 = "[兴趣无好坏,人生各不同]";
Paragraph L1 = new Paragraph();
L1.setFont(new Font(baseFont,10,0));
L1.setSpacingBefore(50);
//设置居中
L1.setAlignment(Element.ALIGN_RIGHT);
L1.add(l1);
//尾缀二
String l2 = "留心智愿";
Paragraph L2 = new Paragraph();
L2.setFont(new Font(baseFont,10,0));
//设置居中
L2.setAlignment(Element.ALIGN_RIGHT);
L2.add(l2);
//最后的时间

DateTimeFormatter dtf = DateTimeFormatter.ofPattern("uuuu/MM/dd");
LocalDate localDate = LocalDate.now();
int year = localDate.getYear();
int monthValue = localDate.getMonthValue();
int dayOfMonth = localDate.getDayOfMonth();
System.out.println(year);
System.out.println(monthValue );
System.out.println(dayOfMonth);

String data = year+"年"+monthValue+"月"+dayOfMonth+"日";
Paragraph Data = new Paragraph();
Data.setAlignment(Element.ALIGN_RIGHT);
Data.setFont(new Font(baseFont,10,0));
Data.add(data);




//将片段加到文档中
document.add(Title);
document.add(P1);
document.add(T1);

document.add(T2);
document.add(T4);
document.add(P3);

document.add(T5);
document.add(P4);

document.add(T6);
document.add(P5);

document.add(T3);
document.add(P6);

document.add(L1);
document.add(L2);
document.add(Data);

document.close();

Map<String, Object> map = new HashMap<>();

map.put("document",document);
map.put("stream",stream);
return map;
}


}

将pdf写到网页的代码

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
package com.dwx.controller;

import com.dwx.pojo.g_hld1;
import com.dwx.pojo.g_hld2;
import com.dwx.pojo.g_report;
import com.dwx.service.hld1Service;
import com.dwx.service.hld2Service;
import com.dwx.service.reportService;
import com.dwx.utils.pdfUtils;
import com.itextpdf.text.*;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayOutputStream;

import java.nio.charset.StandardCharsets;
import java.util.Map;

@Controller
public class ReportController {

//嗲用service层
@Autowired
private reportService reportService;

//调用hld1的service和hld2的service
@Autowired
private hld1Service hld1Service;
@Autowired
private hld2Service hld2Service;


@RequestMapping("/getPDF")
@ResponseBody
public String getPdf(String E,String I,String S,String N,String T,String F,String J,String P,String csrul,HttpServletResponse resp) throws Exception {
//设置下载pdf程序
System.out.println(csrul);
g_report report = reportService.getReport(csrul);
System.out.println(report);

System.out.println(E);
System.out.println(I);
System.out.println(S);
System.out.println(N);
System.out.println(T);
System.out.println(F);
System.out.println(J);
System.out.println(P);

//首先创建一个输出流

//获得我们生成的pdf文档
pdfUtils utils = new pdfUtils();
String profile = report.getPersonalityProfile();
String description = report.getPersonalityDescription();
String career = report.getCareer();
String student = report.getCareerStudent();
String field = report.getField();
Map<String, Object> map = utils.setPDF(E,I,S,N,T,F,J,P,csrul, profile,description,field,student,career );

Document document = (Document) map.get("document");
ByteArrayOutputStream stream = (ByteArrayOutputStream) map.get("stream");


//转化成流 直接输出
resp.setHeader("Content-Disposition", "attachment; filename=" + new String((csrul + ".pdf").getBytes(), StandardCharsets.ISO_8859_1));
resp.setContentLength(stream.size());

ServletOutputStream streamOut = resp.getOutputStream();

stream.writeTo(streamOut);


return "ok";
}


@RequestMapping("/getHldPDF")
@ResponseBody
public String getHldPDF(String R,String C,String E,String S,String A,String I,String d1,String d2,String d3,String dimension,HttpServletResponse resp) throws Exception{


switch (d1){
case "R": d1 = "R现实型";break;
case "C": d1 = "C传统型";break;
case "E": d1 = "E管理型";break;
case "S": d1 = "S社会型";break;
case "A": d1 = "A艺术型";break;
case "I": d1 = "I研究型";break;
default:break;
}
switch (d2){
case "R": d2 = "R现实型";break;
case "C": d2 = "C传统型";break;
case "E": d2 = "E管理型";break;
case "S": d2 = "S社会型";break;
case "A": d2 = "A艺术型";break;
case "I": d2 = "I研究型";break;
default:break;
}
switch (d3){
case "R": d3 = "R现实型";break;
case "C": d3 = "C传统型";break;
case "E": d3 = "E管理型";break;
case "S": d3 = "S社会型";break;
case "A": d3 = "A艺术型";break;
case "I": d3 = "I研究型";break;
default:break;
}
//通过service进行分别的查询
g_hld1 hld1 = hld1Service.getHld1(d1);
System.out.println(hld1);
g_hld1 hld11 = hld1Service.getHld1(d2);
System.out.println(hld11);
g_hld1 hld12 = hld1Service.getHld1(d3);
System.out.println(hld12);

//查询hld2的数据
g_hld2 hld2 = hld2Service.getHld2(dimension);
System.out.println(hld2);


pdfUtils utils = new pdfUtils();
Map<String, Object> map = utils.setHldPDF(R, C, E, S, A, I, d1, d2, d3, hld1, hld11, hld12, hld2);

Document document = (Document) map.get("document");
ByteArrayOutputStream stream = (ByteArrayOutputStream) map.get("stream");


//转化成流 直接输出
resp.setHeader("Content-Disposition", "attachment; filename=" + new String((dimension + ".pdf").getBytes(), StandardCharsets.ISO_8859_1));
resp.setContentLength(stream.size());

ServletOutputStream streamOut = resp.getOutputStream();

stream.writeTo(streamOut);


return "ok";
}



}

代码的细小但重要的代码

1
2
3
4
5
6
7

ByteArrayOutputStream stream = new ByteArrayOutputStream();
//创建一个新的文档
//创建一个空的文档并且设置文档的大小
Document document = new Document(PageSize.A4);

PdfWriter.getInstance(document, stream);

注意这里有个stream流,将pdf转化成流

在这个程序流是在写到网页的时候所需要的

1
2
3
4
5
6
7
8
9
10
11
12
Document document = (Document) map.get("document");
ByteArrayOutputStream stream = (ByteArrayOutputStream) map.get("stream");


//转化成流 直接输出
resp.setHeader("Content-Disposition", "attachment; filename=" + new String((dimension + ".pdf").getBytes(), StandardCharsets.ISO_8859_1));
resp.setContentLength(stream.size());

ServletOutputStream streamOut = resp.getOutputStream();

stream.writeTo(streamOut);

这里就拿到了util方法生成的流和文档 将这个流直接通过springMVC中的HttpService直接将我们的流写到网页上生成文档。

Kruskal算法

Kruskal算法

Kruskal算法是在数据结构书中就已经知晓的一种算法,是生成最小生成树思路中的加边法。

算法的基本思想

给定无向连通带权图G=(V,E),生成最小生成树的基本思想是:

  • 首先将G的n个顶点看成n个孤立的连通分支,将所有的边按权从小到大排序
  • 然后从第一条边开始,依边权递增的顺序查看每条边,并按照上述方法连接两个不同的连通分支
  • 党察看到第k条边(v,w)时,如果端点v和w分别是当前两个不同的连通分支T1和T2中的顶点时,就用链(v,w)将T1和T2连接成一个连通分支,然后继续查看第K+1条边
  • 如果端点V和w在当前的同一连通分支中,就直接再查看第k+1条边
  • 等到只剩下一个连通分支为止,这个连通分支就是G的一棵最小生成树

问题

  • 我们的这个图 现在该怎么存
  • 我们怎么决定两个点之间已经有了联通路
  • 我们怎么回溯返回这个已经创建好的最小生成树

我的手写笔记

我的想法

我的方法

我的学习方法

  1. 自己看书
  2. 看视频

P55-图-6.Kruskal算法_哔哩哔哩_bilibili 这个老师的视频简单易懂

代码

边结构体的代码

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
package passage04;

public class EdgeNode {
//这里为了偷懒 都是用的是整数型
//weight表示边的权重
int weight;
//该边的一个节点
int u;
//v表示该边的另一个节点
int v;

public int getWeight() {
return weight;
}

public void setWeight(int weight) {
this.weight = weight;
}

public int getU() {
return u;
}

public void setU(int u) {
this.u = u;
}

public int getV() {
return v;
}

public void setV(int v) {
this.v = v;
}

public EdgeNode(int u,int v,int weight) {
this.weight = weight;
this.u = u;
this.v = v;
}

public EdgeNode() {
}

@Override
public String toString() {
return "EdgeNode{" +
"weight=" + weight +
", u=" + u +
", v=" + v +
'}';
}
}

Kruskal代码

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
package passage04;

//这是一个最小生成树问题
public class MyKruskal {
//这里我们使用num来表示有几个结点
private int num;

public int getNum() {
return num;
}

public void setNum(int num) {
this.num = num;
}

//这里我们需要的是一个排序
public void edgeSort(EdgeNode[] A){
//使用的是一个冒泡排序
for(int i=A.length-1;i>=0;i--){
for (int j=0;j<i;j++){
if (A[j].weight>A[j+1].weight){
//找到 交换
EdgeNode temp = A[j];
A[j] = A[j+1];
A[j+1] = temp;

}
}
}
}

//这里我们使用树来存放我们已经联结好的图
//首先我们需要一个寻找根节点的算法
//p表示我们想要查找的根节
//V表示我们的并查集
int getRoot(int p,int[] V){
while (V[p] != p){
p = V[p];
}
return p;
}
//合并两个树的方法
//P Q表示要合并的两个节点
void mergeNode(int P,int Q,int[] V){
//这里我规定 我要让标号小的数做父节点
if (P > Q){
V[P] = Q;
}else {
V[Q] = P;
}
}

//Kruskal算法核心
public int Kruskal(EdgeNode[] A){
int sum = 0;
//生成一个合并集
int[] V = new int[num];
//我们规定 如果一个节点是根节点 那么他就存储自己
for (int i=0;i<num;i++){
V[i] = i;
}
//给我们的边的数列排序
edgeSort(A);
//开始找边看看是否合适
for (EdgeNode edgeNode : A) {

//从最小的边开始 向我们的并合集中存数据
int u = edgeNode.getU();
int v = edgeNode.getV();
int P = getRoot(u, V);
int Q = getRoot(v, V);
//如果两个点的根节点不同 那他们就不再一棵数树上 就要合并
if (P!=Q){
sum = sum + edgeNode.weight;
mergeNode(P,Q,V);
//复盘 联结节点
System.out.println("选择双向边从"+edgeNode.u+"到"+edgeNode.v+"权重为"+edgeNode.weight);
}
}
return sum;
}


}

测试代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package passage04;

public class MyKruskalTest {
public static void main(String[] args) {
//创建一个边的集合
EdgeNode node1 = new EdgeNode(0, 1, 1);
EdgeNode node2 = new EdgeNode(0, 2, 5);
EdgeNode node3 = new EdgeNode(0, 3, 6);
EdgeNode node4 = new EdgeNode(1, 2, 8);
EdgeNode node5 = new EdgeNode(1, 4, 4);
EdgeNode node6 = new EdgeNode(2, 4, 2);
EdgeNode node7 = new EdgeNode(2, 3, 7);
EdgeNode node8 = new EdgeNode(4, 5, 9);
EdgeNode node9 = new EdgeNode(3, 5, 3);

EdgeNode[] A = new EdgeNode[]{node1,node2,node3,node4,node5,node6,node7,node8,node9};
MyKruskal myKruskal = new MyKruskal();
myKruskal.setNum(6);
int kruskal = myKruskal.Kruskal(A);
System.out.println(kruskal);

}
}

测试结果

1
2
3
4
5
6
选择双向边从01权重为1
选择双向边从24权重为2
选择双向边从35权重为3
选择双向边从14权重为4
选择双向边从03权重为6
16

静态资源导入以及thymeleaf

静态资源导入以及thymeleaf

因为SpringBoot是在面方法中内置Tomcat,而且它打的包是jar包,因此是没有产生对应的web。那么我们的静态资源放到哪里呐?

静态资源导入

在SpringBoot中有一个XXproperties类,是存放着我们的默认的配置的,当然包括我们的静态资源

这里静态资源的导入一首页为例。

通过那个类,我们可以知道SpringBoot中放置静态资源的有三个地方

  • classpath: /resource/
  • classpath: /static/
  • classpath: /public/
  • classpath:/templates/

在上述的几个地方创建名为index.html的文件,会被默认为是主页

注意:

在其他的文件夹下的网页是可以随意访问的,但是在templates文件夹下的html文件只能通过controller层跳转时候访问到。

ThyMeleaf

这个是一种新式的取值的语言,ThyMeleaf之于SpringBoot相当于JSP之于SSM。

也是取值的一种方式,SpringBoot为它提供了Properties类,也就是说是有默认配置的。

ThyMeleaf的默认配置为,在templates文件夹下的.html文件。

我们可以使用thymeleaf代替所有的Html标签来使用。

尝试

引入依赖

thymeleaf需要引入依赖,在HTML的头文件里

<html xmlns:th="http://www.thymeleaf.org">

语法一会儿学,现在只是进行一个测试

1
2
3
4
5
6
7
8
9
10
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" xmlns:th="http://www.thymeleaf.org">
<title>thymeleafTest</title>
</head>
<body>
<h1 th:text="${msg}"></h1>
</body>
</html>

语法

非官方中文文档Thymeleaf 教程 - Thymeleaf | Docs4dev

在前后端分离时代,很可能前端是别去写的,因此这里我放弃学习这个工具的语法。

SpringBoot预科

SpringBoot预科

SpringBoot是对Spring的一个再简化框架 由于学习比较紧急,因此使用笔记图片作为这篇博客的主力。

SpringBoot学习之HelloWorld

SpringBoot学习之HelloWorld

老习惯,学习一门新的技术或语言都要从helloworld开始。

手写笔记

实际操作

==通过idea进行快速创建,学校的校园网不能连上外网,失败。==

==使用自己的热点成功了==

SpringBoot-HelloWorld

文件介绍

这三个标红的圈从上到下

  • Application:项目的起始位置,不用进行修改
  • application.properties:配置文件,已经做了很多的默认配置
  • test:下的application,是测试程序

编写程序的时候是在Application文件的同级文件夹下编写我们的

  • controller
  • service
  • mapper
  • pojo

等等

HelloWorld的实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package com.dwx.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class HelloWorld {
@RequestMapping("/hello")
@ResponseBody
public String HelloWold(){
return "hello";
}
}

对动态规划的浅薄理解

动态规划

动态规划对于一个算法初学整来说并不好懂,但是通过做题和画图推理,是能够发现动态规划问题的共性的。

最大k乘积问题

问题分析

手推过程

算法实现

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
package com.dwx.passage3;

//十进制数最大k累积
public class demo3_1 {
public int k; //表示子序列分隔的位置
public int i;//表示数组开始的位置
public int j;//表示数组结束的位置
public int m;//表示执行几次划分
public int[][] dp;//存储数据的数组
public int[] l;//存放我们十进制数的整数数组

public int getK() {
return k;
}

public void setK(int k) {
this.k = k;
}

public int getI() {
return i;
}

public void setI(int i) {
this.i = i;
}

public int getJ() {
return j;
}

public void setJ(int j) {
this.j = j;
}

public int[][] getDp() {
return dp;
}

public void setDp(int[][] dp) {
this.dp = dp;
}

public int[] getL() {
return l;
}

public void setL(int[] l) {
this.l = l;
}

public int getM() {
return m;
}

public void setM(int m) {
this.m = m;
}

//这个问题的动态规划方法
public void demo(){
//先对我们获得的数组进行初始化
//一般第一列和第一行我们都跳过不进行初始化 为了方便理解将数字中的i与我们计算机中的第i列相对应
int a,b,c,d;
for (a = i;a <= j; a++){
dp[a][1] = getNumber(i,a);
}
//对除了第一行以外的其他的元素进行操作

//对第二列进行操作
for (b=2;b<=m;b++){
for (c = 2;c<=(j-i)+1;c++){
int max = 0;
for (k=c-1;k>=1;k--){
if (dp[k][b-1]*getNumber(k+1,c)>max)
max = dp[k][b-1]*getNumber(k+1,c);
}
dp[c][b] = max;
}
}

}




//先编写一个获取数值的方法
int getNumber(int i,int j){
int number = 0;
int x = 1;
for (int k = j;k>=i;k--){
number = number + l[k]*x;
x = x * 10;
}
return number;
}
}

验证

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
import com.dwx.passage3.demo3_1;

public class demo3_1Test {
public static void main(String[] args) {
int i = 1;
int j = 4;
int m = 4;
int dp[][] = new int[5][5];
int[] l = new int[]{0,1,2,3,4};
demo3_1 demo3_1 = new demo3_1();
demo3_1.setDp(dp);
demo3_1.setI(i);
demo3_1.setJ(j);
demo3_1.setL(l);
demo3_1.setM(m);
demo3_1.demo();
int[][] dp1 = demo3_1.getDp();
for (i=1;i<=j;i++){
for (int x=1;x<=j;x++){
System.out.print(dp1[i][x]+"\t");
}
System.out.println();
}

}
}

输出

1
2
3
4
1	0	0	0	
12 2 0 0
123 36 6 0
1234 492 144 24

我们可以看到,我们的输出和我们手推的结果一样,因此这个算法程序是正确的。

总结

从上边的的几个案例我们可以看到,动态规划就是一个空间换时间的算法思路。动态规划求一个问题的最优解也是把整个问题的所有情况全部遍历了一边,但是比起一般的遍历,动态规划因为使用了dp矩阵,因此之前计算过的情况全部存放在dp矩阵里,减少了计算的次数,因此有人说动态规划是一种带记忆的遍历。

动态规划的解题思路是:

  • 找到递推公式
  • 确定dp矩阵的行向量和列向量的含义
  • 自底而上一步步求解一步步动态规划
  • 就得到了一个东西的所有情况

动态规划并没有一个固定的算法,不能和之前在数据结构中学习到的算法混为一谈。

在我看来动态规划只是一种思路,这种思路需要逻辑性。

最快学会学清除动态规划的方法就是,自己把一个动态规划题目的dp矩阵手推出来

就能理解程序的处理过程了。

石子合并问题

石子合并问题

问题背景

(105条消息) dp算法 - 石子合并问题_lost_tower的博客-CSDN博客_石子合并

他的这个收算法解释的,但是我们保证我写的是我自己思考出来的。

这里我只是借用他的写出来的问题

问题分析

这个是思考这个题时候的笔记,有手推过程,以及递推公式


手推过程

算法实现

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
package com.dwx.passage3;

public class demo3__3 {
private int m[];//m数组说是用来存放石头的
private int dp[][];//用来存放合并后的石头堆
private int i;//起始地址
private int j;//终止地址

int inf = 9999;

public int[] getM() {
return m;
}

public void setM(int[] m) {
this.m = m;
}

public int[][] getDp() {
return dp;
}

public void setDp(int[][] dp) {
this.dp = dp;
}

public int getI() {
return i;
}

public void setI(int i) {
this.i = i;
}

public int getJ() {
return j;
}

public void setJ(int j) {
this.j = j;
}


//这个是动态规划方法的主体
//这个递归程序用来求最小代价
public void demoMin(){
//对程序进行初始化
//计算石头的数量
int n = m.length;
//不需要任何的初始化
//初始化 都化为0
for (int d = 1;d<n;d++){
for (int e=1;e<n;e++){
dp[d][e] = 0;
}

}

//对除了对角线以外的数据进行操作
//这里 我们设a为列,b为行,c为间断点
//因此 我们的思想是 从a合并到b,以c为间断点
int a,b,c;
int min;
for (b=2;b<m.length;b++){
for (a=b-1;a>=1;a--){
min = inf;
//设置间断点
for (c=b-1;c>=a;c--){
if (dp[a][c]+dp[c+1][b]+getNumber(a,b) < min){
min = dp[a][c]+dp[c+1][b]+getNumber(a,b);
}
}
dp[a][b] = min;
}
}
}
//这个程序用来求最大代价
public void demoMax(){
//对程序进行初始化
//计算石头的数量
int n = m.length;
//不需要任何的初始化
//初始化
for (int d = 1;d<n;d++) {
for (int e = 1; e < n; e++) dp[d][e] = 0;


} //对除了对角线以外的数据进行操作
//这里 我们设a为列,b为行,c为间断点
//因此 我们的思想是 从a合并到b,以c为间断点
int a,b,c;
int max;
for (b=2;b<m.length;b++){
for (a=b-1;a>=1;a--){
max = 0;
//设置间断点
for (c=b-1;c>=a;c--){
if (dp[a][c]+dp[c+1][b]+getNumber(a,b) > max){
max = dp[a][c]+dp[c+1][b]+getNumber(a,b);
}
}
dp[a][b] = max;
}
}
}

//这个是获得合并后石头数量的方法
public int getNumber(int i,int j){
int number = 0;
for (int k=i;k<=j;k++){
number = number+m[k];
}

return number;
}
}

检验

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
import com.dwx.passage3.demo3__3;

public class demo3_3Test {
public static void main(String[] args) {
//设置数组
int[] m = new int[]{0,5,8,2,9,3,6,4};
//设置dp数组
int[][] dp = new int[m.length][m.length];
// 设置起始位置和终止位置
int i = 0;
int j = 0;
demo3__3 demo3__3 = new demo3__3();
demo3__3.setDp(dp);
demo3__3.setI(i);
demo3__3.setJ(j);
demo3__3.setM(m);
//执行找最小代价程序
demo3__3.demoMin();
int[][] dp1 = demo3__3.getDp();
for (int[] ints : dp1) {
for (int anInt : ints) {
System.out.print(anInt+"\t");
}
System.out.println();
}
System.out.println("==============================");
//执行找最大代价的程序
demo3__3.demoMax();
int[][] dp2 = demo3__3.getDp();
for (int[] ints : dp2) {
for (int anInt : ints) {
System.out.print(anInt+"\t");
}
System.out.println();
}

}
}

输出结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
0	0	0	0	0	0	0	0	
0 0 13 25 48 64 85 106
0 0 0 10 29 44 65 83
0 0 0 0 11 25 40 57
0 0 0 0 0 12 27 44
0 0 0 0 0 0 9 22
0 0 0 0 0 0 0 10
0 0 0 0 0 0 0 0
==============================
0 0 0 0 0 0 0 0
0 0 13 28 54 81 114 151
0 0 0 10 30 52 80 112
0 0 0 0 11 26 50 76
0 0 0 0 0 12 30 52
0 0 0 0 0 0 9 23
0 0 0 0 0 0 0 10
0 0 0 0 0 0 0 0

可以看到这个结果和我们的手推的dp矩阵时一致的,因此是一个合适的答案

不足之处

在编写动态规划问题的时候,思考最多的是地推公式,应该仔细分析,得到一个正确的递归公式。

得到递归公式也不代表是解决了这个问题,要分析好这个三重for循环怎么写,算法实现怎么写。

一定要注意,动态规划自底而上的原则

在分析递推公式的时候一定要注意:

dp[i] [j]矩阵的i和j到底代表着什么

矩阵连乘问题

矩阵连乘

矩阵连乘是一个经典的动态规划问题

矩阵连乘的思想

算法实现

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
package com.dwx.passage3;

public class MatrixChain {
//整数矩阵连乘
/*
* p[]: 输入参数
* m[]:最优值数组
* s[]:最优断开位置数组
* r:子链长度
* n:我们要求的链的长度*/
private int[] p;
private int[][] m;
private int[][] s;
private int r;
private int n;

public int[] getP() {
return p;
}

public void setP(int[] p) {
this.p = p;
}

public int[][] getM() {
return m;
}

public void setM(int[][] m) {
this.m = m;
}

public int[][] getS() {
return s;
}

public void setS(int[][] s) {
this.s = s;
}

public int getR() {
return r;
}

public void setR(int r) {
this.r = r;
}

public int getN() {
return n;
}

public void setN(int n) {
this.n = n;
}

//算法核心
public void matriChain(){
//对矩阵进行初始化 将m[][]的对角线全部设置为0
for (int i=1;i<=n;i++) {
m[i][i] = 0;
}
//对网格图m[][]填写数据
for (int r = 2;r<=n;r++){
for (int i=1;i<=n-r+1;i++) {
int j = i + r - 1;
m[i][j] = m[i + 1][j] + p[i - 1] * p[i] * p[j];
s[i][j] = i;

for (int k = i + 1;k<j;k++){
int t = m[i][k] + m[k+1][j] + p[i-1]*p[k]*p[j];
if (t<m[i][j]){
m[i][j] = t;
s[i][j] = k;
}
}
}
}

}

//回溯查找动态规划
public void traceBack(int i,int j){
if (i==j)
System.out.print("A"+i);
else if (i+1 == j)
System.out.print(" (A"+i+"*"+" A"+j+") ");
else {
System.out.print(" (");
traceBack(i,s[i][j]);
traceBack(s[i][j]+1,j);
System.out.print(") ");
}
}
}

其中traceBack方法是用来回溯找到最优解的。

  • Copyrights © 2015-2023 dwx
  • Visitors: | Views:

请我喝杯咖啡吧~

支付宝
微信