分类

课内:
不限
类型:
不限 毕业设计 课程设计 小学期 大作业
汇编语言 C语言 C++ JAVA C# JSP PYTHON PHP
数据结构与算法 操作系统 编译原理 数据库 计算机网络 软件工程 VC++程序设计
游戏 PC程序 APP 网站 其他
评分:
不限 10 9 8 7 6 5 4 3 2 1
年份:
不限 2018 2019

资源列表

  • 基于Face++的人脸融合及换脸系统

    1.项目介绍在本项目中,我们实现了对人脸图片数据的三种处理:人脸互换(face swap)、人脸融合(face morph)以及基于特征向量的人脸处理(eigen face)。
    1.1 人脸互换(face swap)人脸互换部分主要实现的功能是,给定任意两张人脸图片,通过一系列操作,使两个人的脸部交换,这部分需要的问题有:

    不同的人的脸部结构千差万别,同一个人也会因为角度、面部表情的不同而导致差别,即如何实现不同图片的人脸对齐
    不同人脸的肤色、光照不同,即不同图片的面部亮度不同,在换脸后如何与整体亮度统一
    不同人脸的纹理不同,比如老人的皱纹等,如何实现换脸后纹理的统一

    1.2 人脸融合(face morph)在人脸融合部分,我们需要实现给定任意两张人脸图片和融合度α,通过一系列操 作,实现两个人脸的融合。这一部分的困难在于:

    人脸结构的检测与分割。对于给定的人脸图片,人脸的结构差异很大
    人脸融合度的构建。对于给定的融合度 α,如何对两张图片的人脸取样与映射

    1.3 本征脸(eigen face)在这一部分,需要对较大的数据集(几百张,几千张人脸图片)进行处理,通过主成分分析的方法,得到一定数量的人脸主成分。这一部分的主要困难在于数据集的预处理,我们需要将不同图片中的人脸对齐,才能进行后续的处理。
    2.算法结构与处理过程2.1 人脸变换2.1.1 人脸关键点检测实现人脸变换的第一步,便是人脸关键点的检测,得到图片中的人脸的结构。在这 里,我们利用旷视face++的API来定位人脸关键的集合{V1,V2,…,Vn},其中关键点的数量可 以选择 83 或者 106。
    左:人脸关键点与凸包;右:德劳内三角集。

    2.1.2 计算凸包在获取人脸关键点集合后,我们需要计算这些关键点的凸包(convex hull)(凸包是一个计算几何(图形学)中的概念:在一个实数向量空间 V 中,对于给定集合 X,所有包含 X 的凸集的交集 S 被称为 X 的凸包。X 的凸包可以用 X 内所有点(X1,…Xn)的凸组合来构造.)在这里,我们计算凸包是为了获取这些人脸关键点组成的一个人脸区域。
    2.1.3 德劳内(Delaunay)三角划分在获得凸包以后,我们对凸包内的人脸关键点进行德劳内三角的划分。德劳内三角划分能将我们的凸包区域进行分割,并且更易于保留人脸的细节部分,并且因为获取仿射变换需要原图片和目标图片的各三个点,正好对应于原图和目标图的对应的德劳内三角。
    2.1.4 进行仿射变换在获得原图片和目标图图片的德劳内三角以后,我们需要寻找两张图对应的三角形对,对这样的每一对三角形,我们可以计算得到一个仿射函数。这个仿射函数将被用于三角形对之间的仿射变换。重复这个操作,直到所有区域都操作完毕,我们得到了人脸的位置变换。
    2.1.5 无缝融合在上述人脸仿射变换后,我们得到人脸结构和位置的变换,但我们没有对人脸区域亮度进行调整,这样会造成人脸区域和其他区域的颜色协调的问题。所以最后我们用 opencv 的无缝融合函数 seamlessClone()来实现无缝融合操作。
    2.2 人脸融合2.2.1 人脸关键点检测和 2.1.1 部分一样,我们首先需要确定给定图片的人脸的结构,所以需要检测人脸的关键点。在这里我们仍然使用旷视 face++的人脸关键点识别 API,选择 108 点检测。
    2.2.2 定义融合度要实现两张人脸的融合,我们还要定义融合度 α(0=<α<=1):

    M 是融合后的图像,I,J 是两张待融合图像。我们定义 α,使 α 趋于 0 使,越来越接近图 像 I;α 趋于 1 时,越来越接近图像 J;α 等于 0.5 时,相当于两张图像的平均。
    2.2.3 采样点加权在获得两张人脸的关键点后,我们再对两张人脸进行加权平均:

    通过这个式子,我们计算加权后的人脸关键点的位置。
    左:采样点加权后的人脸结构;右:德劳内三角划分。

    2.2.4 德劳内三角划分如同 1.1.3,我们对获取的人脸关键点进行德劳内三角划分,不同的是,我们为了获取人脸框架结构在整张图中的位置,需要手动添加图片四个角以及四边中心点作为辅助点,再进行德劳内三角划分。这样,我们就得到非常详细的人脸结构。
    2.2.5 图像融合在经过以上步骤后,我们进行人脸融合。首先,我们对源图像的人脸关键点对我们在 2.2.3 中得到的加权后的人脸关键点进行仿射变换。由对应的德劳内三角形确定的三个点,我们可以确定一个仿射变换;对所有的三角形进行这样的操作,我们就得到了仿射后的人脸图片。对两张源图进行这样的操作,我们就得到两个仿射后的人脸图片,再运用我们定义的融合度 α 进行加权平均,最终得到我们的目标图片。

    2.3 本征脸2.3.1 数据预处理此次我们用于测试的数据集有两个,一个是 NBA 现役球员,另一个是女外女明星。对于我们的人脸图片数据集,我们首先要做的是将它们的大小固定为统一的大小。然后,我们需要将每张人脸配准定位,一个方法是将每张图片的人的眼睛定位于同一水平线上,并且使每张图片的两眼中心点在相同的位置。
    2.3.2 主成分分析在预处理图片后,我们对图片的数据进行主成分分析。首先,对于每张 NxN 大小的图片,我们将其转化成一个(NxNx3)x 1 的向量。当有 M 张图片时,我们便有一个(NxNx3)x M 的矩阵。
    在计算主成分之前,我们先来对我们的图片矩阵数据求平均值向量,这是为了后面的方差和协方差准备的。在获取了平均值向量之后,我们来计算主成分。在数数学上,我们通过线性代数中的矩阵特征值分解,可以找到矩阵的特征值和相应的特征向量,我们将这些特征值按从大到小排列,越大的特征值说明数据在这个特征值对应的特征向量的方向上 的方差越大,这就是我们要找的主成分。在这里,我们可以设置参数,来选择主成分的数量。例如,我们选择前十大的特征值和对应的特征向量。
    2.3.3 获得本征脸在获得主成分之后,我们将选取的主成分矩阵,按原来图片矩阵转化为向量的逆操 作,将矩阵变成图片矩阵。
    3.代码结构3.1 人脸互换相关文件:faceswap.py

    get_points 函数。用于封装好 Face++的 API,得到图片的 83 个人脸特征点,并存储在一个列表当中,方便后续处理
    AffineTransform 函数。该函数输入源图、源图的德劳内三角、目标图的德劳内三角和给定的大小。通过计算获取仿射变换函数,并且进行仿射变换,输出变换后的图片
    DelaunayTriangles函数。用于计算我们人脸关键点的德劳内三角。我们应用openCV的Subdiv2D 函数,可以得到我们的德劳内三角
    warpTriangle 函数。通过德劳内三角的划分,我们定义这个函数,用来实现对德劳内三角的仿射变换,并且最终将左右变换后的三角形区域合并,得到我们的目标脸
    最后是主函数,调用这些定义好的函数,读取我们的图片进行处理

    3.2 人脸融合有关文件:morph.py

    detect 函数。用于封装好 Face++的 API,得到图片的 108 个人脸特征点,并存储在一个字典当中,方便后续处理
    addBorderPoints 函数。该函数功能是给处理图片准备要划分三角形的时候,把图片四个顶点和四条边的中点的坐标添加到带划分的点中,这让得劳内三角形能完整的划分 整张图片
    delaunaryTriangles 函数。由特征点的坐标生成其用来划分这些特征点的得劳内三角形
    affineTransform 函数。根据划分好的三角形,我们可以用来计算一张图的三角形到另外一张图所对应的三角形的仿射变换,该函数在 morphingTriangle 函数中使用
    morphingTriangle 函数。对两个仿射后的人脸图片,运用我们定义的融合度 α 进行加权平均,最终得到我们的目标图片


    morphing 函数。总的融合函数的接口,得到融合图片的脸部特征点的坐标,与新图片的脸部划分三角形坐标,调用 morphingTriangle 函数得到新的融合图片
    getPic 函数。用于实现 GUI 中根据 alpha 生成一张图片的功能
    get20Pics,create,sortKey,createGIF 函数。用于实现 GUI 生成一张 gif 图片的功能

    3.3 本征脸人脸相关文件:eigenface_origin.py

    readImages 函数。从指定的文件夹中读取图片文件,将其转化成 numpy 矩阵,放到一个 list 中。在此过程中,每张图片翻转后又保存了一次
    createdatamatrix 函数。将保存图片的 numpy 矩阵压平。(每张图片压平)
    createnewface 函数。产生特征脸并且用 opencv 可视化界面展示
    resetslidervalues 函数。在 opencv 可视化界面中,点击一下图片,就重置所有 bar
    总体思路:从文件夹中读取图片,变成矩阵,每张图片 flatten,用求平均向量,特征向量,再计算出 eigenface。

    3.4 GUI 部分有关文件:

    mainPage.py 主界面 GUI
    morphGUI.py 融合脸功能界面 GUI
    swapGUI.py 换脸功能界面 GUI
    eigenGUI.py 特征脸界面 GUI

    4.开发环境在本次项目中,算法几接口 API 都是由 pyhton3.5(python3.6)完成的,其中还使用了openCV 库。GUI 使用 pyqt 完成。API 使用 face++人脸关键点接口。
    5.可执行文件及使用的数据集5.1 数据集我们有 2 个数据集,其中一个 image_swap 是用于测试换脸操作的;另外一个 image_eigen 数据集是用来测试本征脸的,是 NBA 现役球员的图片。人脸融合测试图片,一定要是放在与该py文件夹中相同的文件夹,所以没有专门的数据集,可以从其他地方复制一些图片,进行测试。
    5.2 可执行文件及运行方式在 windows 下,我们有可执行文件 face#.exe。执行方式:双击打开,会看到我们 GUI 的初始界面。在界面中我们会看到三个按钮,这是我们 GUI 实现的三个功能,及人脸互换、人脸融合和本征脸。点击其中一个按钮,会进入下一层界面,具体的操作可以参考我们附加提交的操作演示视频。




    在 macOS 系统下,可以通过 python 文件名.py 命令运行我们的 python 文件。
    6.项目成果与反思6.1 项目成果6.1.1 人脸互换
    从测试结果图中,我们可以看到,我们的人脸互换效果还是非常好的:从前景图上截取的脸部,能够非常好地与背景图融合;在边缘部分,没有明显的边界;在人脸的姿势上,也根据背景的姿势得到了调整,能够与背景姿势相一致。当然我们也可以看到,在第二个结果中,由于前景脸和背景脸的脸部颜色相差太大,导致结果图中的脸部与额头等地方有明显的不一致,这是因为我们在做人脸互换的时候,只根据人脸关键点确定的凸包进行变换,而人脸关键点是没有包含额头及脖子部分的。这是我们人脸互换做的不好的地方
    6.1.2 人脸融合
    同样,对于我们人脸融合的结果,也非常好。在它融合度为 0.5 的情况下,包含了两张源图中一样多的特征,让我们能在结果图中能找到明显的属于两张源图的特征。但是同样存在一些问题,比如在上面一张结果中,我们可以看到头发部分有重影。这是因为两张源图片的头发差异部分存在白色的背景,当进行融合时,由于有两部分的特征,所以会造成重影;但是第二张结果图中,我们没有看到这个现象,这是因为两张源图的差异部分没有很白的背景颜色。
    6.1.3 本征脸
    对于我们的本征脸,我们在此解释一下左侧拖条的含义:首先我们这部分是对人脸数据集进行主成分分析,所谓的主成分就是数据中方差最大的一些方向,对应到人脸数据中,便是影响数据集中人脸的形态的最大的方向,或者说数据集中人脸变化最大的一些特征。比如,NBA 球员数据集中,球员的肤色有黑有白,这是变化非常大的特征,所以应该会有一个主成分只指向球员肤色的黑白的。而之所以右侧的结果会很模糊,正是因为我们计算出的主成分代表了人脸数据集中变化最大的特征,所以这些特征组成的图片必定是非常模糊非常不整齐的。
    6.2 项目思考与改进6.1.1 人脸互换我们的人脸互换算法依赖于人脸关键点锁定的区域,基本上限定于眉毛-两侧脸颊-下巴组成的区域,当两张源图的脸部颜色差别很大时,会出现结果图中脸部与额头差别很大的问题。所以,我们设想后续的优化是,将脸部的区域扩大到额头,乃至整个脖子,但是由于一般人脸检测的算法只限于原先的区域,如何检测这些扩展的区域,是一个较难解决的问题。
    6.1.1 人脸融合对于人脸融合中出现的结果图中脸部区域以外的重影问题,我们设想的优化是,将脸部以外的区域,全部设置成其中一张源图的背景区域。
    6.2.3 本征脸对于主成分分析得出来的若干个对人脸变化影响最大的特征,其中一些我们能够直观地看出来,例如肤色的黑白等,但有一些特征并不能很容易地得知与什么相关,需要我们进一步测试、观察与分析。
    2 评论 22 下载 2019-05-24 10:28:03 下载需要11点积分
  • 基于JAVA和SQL SERVER数据库实现的医院病房信息管理系统

    1 系统设计1.1 设计目标医院病房管理系统是一种以窗体界面为基础的多功能平台,本系统最根本的目的是让使用者与数据库能够通过系统达到交互,以此来进行医院病房的管理等相关操作。管理员可以通过该平台对医生、病人、科室、病房、病床进行增加、删除、修改、查询操作,普通用户可以通过该平台查看修改自己的个人信息、进行病人住院登记、查询病人和床位信息、根据病人的住院日期、出院日期和所住病房的收费标准进行出院结算,然后删除该病人的信息。本系统在全面提高医院的整体工作效率、为病人提供快捷的服务、为医生提供人性化的管理、减轻医院工作人员的负担等方面发挥着重要作用。
    1.2 需求分析信息要求:医生基本信息包括工作证号、密码、姓名、性别、职称、年龄、联系电话、所属科室,病人基本信息包括病历号、姓名、性别、诊断结果、病房号、病床号、主治医生工作证号、联系电话、入院日期、出院日期,科室基本信息包括科室名称、科室地址、科室电话,病房基本信息包括病房号、所属科室、收费标准,病床基本信息包括病房号、病床号、目前状态。
    处理要求:一名医生可以诊治多名病人,一名病人只能被一名医生诊治。一个病房可以住多名病人,一名病人只能住在一个病房。一个科室有多名医生,一个医生只属于一个科室。一个科室包含多个病房,一个病房只属于一个科室。一个病房拥有多张病床,一个病床只能位于一个科室。
    安全性与完整性要求:管理员和医生只有输入正确的工作证号和密码才能登录系统,如果还没有注册,先输入相关信息进行注册。对于管理员,管理主页列出了管理员所能实现的功能,包括对医生、病人、科室、病房、病床的增加、删除、修改、查询,管理员根据需要选择对应的项目。对于用户,即医生,管理主页列出了医生所能实现的功能,包括查看修改自己的个人信息、登记病人基本信息、查询病人和床位信息、根据病人的住院日期、出院日期和所住病房的收费标准进行出院结算,然后删除该病人的信息。为了保证系统的安全性,系统提供对工作证号和旧密码的验证,来修改登录密码。
    1.3 开发和运行环境选择
    开发工具:前台开发语言为Java编程语言
    后台数据库为SQL Server 2014
    运行环境:Windows 10

    2 数据库设计2.1 数据库概念设计根据需求分析,可以确定该系统中的实体、属性和联系之间的关系,并画出如下所示的E-R图。
    实体及属性如图2.1所示。

    病人实体及属性如图2.2所示。

    科室实体及属性如图2.3所示。

    病房实体及属性如图2.4所示。

    病床实体及属性如图2.5所示。

    由该项目的处理需求可知,“医生”和“病人”之间的“治疗”联系为1:n,即一名医生可以诊治多名病人,一名病人只能被一名医生诊治。“病房”和“病人”之间的“入住”联系为1:n,即一个病房可以住多名病人,一名病人只能住在一个病房。“科室”和“医生”之间的“属于”联系为1:n,即一个科室有多名医生,一个医生只属于一个科室。“科室”和“病房”之间的“包含”联系为1:n,即一个科室包含多个病房,一个病房只属于一个科室。“病房”和“病床”之间的“拥有”联系为1:n,即一个病房拥有多张病床,一个病床只能位于一个科室。系统的实体联系图,如图2.6所示。

    2.2 数据库逻辑结构设计2.2.1 关系模式根据转换规则和医院病房管理系统E-R图,可以得到医院病房管理系统的关系模式如下。
    医生(工作证号、密码、姓名、性别、职称、年龄、联系电话、所属科室)为医生实体对应的关系模式,其中工作证号是主码,科室的主码科室名称是医生的外码。
    病人(病历号、姓名、性别、诊断结果、病房号、病床号、主治医生工作证号、联系电话、入院日期、出院日期)为病人实体对应的关系模式,其中病历号是主码,医生的主码工作证号是病人的外码属性,病床的主码病房号、病床号是病人的外码属性。
    科室(科室名称、科室地址、科室电话)为科室实体对应的关系模式,其中科室名称是主码。
    病房(病房号、所属科室、收费标准)为病房实体对应的关系模式,其中病房号是主码,科室的主码科室名称是病房的外码。
    病床(病房号、病床号、目前状态)为病床实体对应的关系模式,其中病房号、病床号是主码。
    2.2.2 结构设计表医生结构设计表如表2.1所示。

    病人结构设计表如表2.2所示。

    科室结构设计表如表2.3所示。

    病房结构设计表如表2.4所示。

    病床结构设计表如表2.5所示。

    2.2.3 数据字典数据项描述如表2.3所示。

    数据结构描述如表2.4所示。

    3 医院病房管理系统详细设计3.1 系统功能医院病房管理系统主要分为用户模块和管理员模块(分为医生、病人、科室、病房、病床信息增删改查功能)。其中用户模块包括查看修改自己的个人信息、进行病人住院登记、查询病人和床位信息、根据病人的住院日期、出院日期和所住病房的收费标准进行出院结算,然后删除该病人的信息。管理员模块包括对医生、病人、科室、病房、病床进行增加、删除、修改、查询操作。
    3.2 数据库以及表的建立医院病房管理系统数据库中包含五张表,分别为医生(Doctor)、病人(Patient)、科室(Department)、病房(Ward)、病床(Bed),相关代码如下。
    CREATE TABLE Doctor (Dno CHAR(10) PRIMARY KEY, Dpassword VARCHAR(15) NOT NULL, Dname CHAR(20) NOT NULL, Dsex CHAR(2) NOT NULL, Dtitle CHAR(10) NOT NULL, Dage SMALLINT NOT NULL, Dtel CHAR(11) NOT NULL, Deptname CHAR(20) NOT NULL, FOREIGN KEY(Deptname) REFERENCES Department(Deptname) );CREATE TABLE Department (Deptname CHAR(20) PRIMARY KEY, Deptaddress CHAR(20) NOT NULL, Depttel CHAR(11) NOT NULL );CREATE TABLE Ward (Wno CHAR(9) PRIMARY KEY, Deptname CHAR(20) NOT NULL, Wcharge INT NOT NULL, FOREIGN KEY(Deptname) REFERENCES Department(Deptname) );CREATE TABLE Bed (Wno CHAR(9), Bno CHAR(9), Bstate CHAR(20) , PRIMARY KEY(Wno,Bno), FOREIGN KEY(Wno) REFERENCES Ward(Wno) );CREATE TABLE Patient (Pno CHAR(10) PRIMARY KEY, Pname CHAR(20) NOT NULL, Psex CHAR(2) NOT NULL, Pdiagnose CHAR(20) NOT NULL, Wno CHAR(9) NOT NULL, Bno CHAR(9) NOT NULL, Dno CHAR(10) NOT NULL, Ptel CHAR(11) NOT NULL, Pindate DATE NOT NULL, Poutdate DATE , FOREIGN KEY(Wno,Bno) REFERENCES Bed(Wno,Bno), FOREIGN KEY(Dno) REFERENCES Doctor(Dno) );
    3.3 连接数据库连接数据库的代码及设置和连接操作的相关代码如下。
    package linkdatabase;package linkdatabase;import java.sql.Connection;import java.sql.DriverManager;import java.sql.PreparedStatement;import java.sql.ResultSet;import java.sql.SQLException;public class linkdatabase { static Connection connection; public linkdatabase(){ //数据库驱动 String driverName="com.microsoft.sqlserver.jdbc.SQLServerDriver"; //连接的数据库 String url="jdbc:sqlserver://localhost:1433;DatabaseName=HWMS"; String user="sa"; String password="yyl13593519418"; //加载JDBC-MySQL数据库驱动 try { Class.forName(driverName); connection = (Connection) DriverManager.getConnection(url,user,password); System.out.println("数据库连接成功"); } catch(Exception e) { e.printStackTrace(); System.out.println("数据库连接失败:"+e.getMessage()); } } public static Connection getConnection(){ new linkdatabase(); return connection; } public void setConnection(Connection connection){ this.connection = connection; } public static void closeAll(ResultSet rs,PreparedStatement ps,Connection con){ if(rs != null){ try{ rs.close(); }catch(SQLException e){ e.printStackTrace(); } } if(ps != null){ try{ ps.close(); }catch(SQLException e) { e.printStackTrace(); } } if(con != null){ try{ con.close(); }catch(SQLException e){ e.printStackTrace(); } } }}
    3.4 登录系统登录系统为进入系统的首要操作,相关代码如下。
    package Hospitallogin;import java.awt.Button;import java.awt.Color;import java.awt.Cursor;import java.awt.Font;import java.awt.event.ActionEvent;import java.awt.event.ActionListener;import java.awt.event.WindowAdapter;import java.awt.event.WindowEvent;import java.sql.Connection;import java.sql.PreparedStatement;import java.sql.ResultSet;import javax.swing.ImageIcon;import javax.swing.JFrame;import javax.swing.JLabel;import javax.swing.JOptionPane;import javax.swing.JPanel;import javax.swing.JTextField;import Doctorfunction.Main;import Hospitaladmin.admin_frame;import Hospitalresponse.Alter;import Hospitalresponse.Register;import geng.handle.HandleLogin;import geng.model.Login;import linkdatabase.linkdatabase;public class LoginFrame extends JFrame implements ActionListener{ String sql; Login login = new Login(); HandleLogin handleLogin = new HandleLogin(); JLabel l1 = new JLabel("欢迎登陆医院病房管理系统"); JLabel l2 = new JLabel("账号:"); JLabel l3 = new JLabel("密码:"); JLabel l4 = new JLabel("账号不存在!"); JLabel l5 = new JLabel("<HTML><U>"+"注册账号"+"</U></HTML>"); JLabel l6 = new JLabel("<HTML><U>"+"修改密码"+"</U></HTML>"); JTextField t1 = new JTextField(); JTextField t2 = new JTextField(); Button b1 = new Button("登陆"); Button b2 = new Button("取消"); public LoginFrame() { // TODO Auto-generated constructor stub //设置标题 super("欢迎登陆医院病房管理系统");//创建标题为欢迎登陆医院病房管理系统的窗口 setBounds(300,100,910,500);//设置窗口在屏幕上的位置及大小 String path = "lib/login.jpeg"; ImageIcon backgroundimage=new ImageIcon(path);//使标签有图片,用此创建背景图片 JLabel jLabel = new JLabel(backgroundimage);//标签为用户提示信息 jLabel.setBounds(0, 0, this.getWidth(), this.getHeight());//标签在窗口上的位置及大小 JPanel jPanel1 = (JPanel) this.getContentPane();//初始化一个内容面板,这样才可以把内容面板设置成透明的 jPanel1下面是我们要添加的图片,上面是我们的组件 jPanel1.setOpaque(false);//使组件不会显示其中的某些像素,允许组件下面的像素显现出来,即设置透明 jPanel1.setLayout(null); this.getLayeredPane().add(jLabel,new Integer(Integer.MIN_VALUE)); setVisible(true); // 登陆界面配置 l1.setBounds(450, 70, 450, 35); l1.setFont(new Font("宋体", Font.BOLD, 30)); l2.setBounds(470, 140, 70, 25); l2.setFont(new Font("宋体",Font.BOLD,23)); l3.setBounds(470, 200, 70, 25); l3.setFont(new Font("宋体",Font.BOLD,23)); l4.setBounds(120, 200, 150, 20); l4.setFont(new Font("宋体",Font.BOLD,23)); l5.setBounds(730,140,70,25); l5.setFont(new Font("微软雅黑",Font.BOLD,15)); l5.setForeground(Color.blue); l5.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); l5.addMouseListener(new Register()); l6.setBounds(730,200,70,25); l6.setFont(new Font("微软雅黑",Font.BOLD,15)); l6.setForeground(Color.blue); l6.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); l6.addMouseListener(new Alter()); t1.setBounds(540, 140, 160, 25); t1.setFont(new Font("宋体",0,18)); t2.setBounds(540, 200, 160, 25); t2.setFont(new Font("宋体",0,18)); b1.setBounds(540, 260, 70, 30); b1.setFont(new Font("宋体",0,15)); b1.addActionListener(this); b2.setBounds(660, 260, 70, 30); b2.setFont(new Font("宋体",0,15)); b2.addActionListener(this); super.add(l1); super.add(l2); super.add(l3); super.add(l5); super.add(l6); super.add(t1); super.add(t2); super.add(b1); super.add(b2); super.setLayout(null); super.setVisible(true); //当单击窗口右上方的关闭图标时,监视器调用windowClosing方法,如果在该方法中使用System.exit(0)退出程序的运行 super.addWindowListener(new WindowAdapter() { @Override public void windowClosing(WindowEvent e) { // TODO Auto-generated method stub super.windowClosing(e); System.exit(0); } }); super.setResizable(false); } public static void main(String[] args) { // TODO Auto-generated method stub new LoginFrame(); } @Override //事件源触发ActionEvent事件后,监视器调用接口中的此方法对发生的事件做出处理 public void actionPerformed(ActionEvent e) { // TODO Auto-generated method stub Object source = e.getSource();//返回添加事件监听的对象 Connection con = null; PreparedStatement ps = null; ResultSet rs = null; if(source == b1) { String name = t1.getText(); String pass = t2.getText(); Login login = new Login(); login.setDno(name); try { con = linkdatabase.getConnection(); if("".equals(name.trim()) || "".equals(pass.trim())) { JOptionPane.showMessageDialog(null, "请输入完整的登陆信息!","系统提示",JOptionPane.ERROR_MESSAGE); }else if(name.equals("admin") && pass.equals("123456")) { new admin_frame(); super.dispose(); }else { login.setDno(name); login.setDpassword(pass); login = handleLogin.queryVerify(login); if(login.getLoginSuccess() == true) { System.out.println("登录成功了!"); new Main(login); super.dispose(); }else { System.out.println("登录失败了!"); JOptionPane.showMessageDialog(null, "登录失败,请重新登录","系统提示",JOptionPane.WARNING_MESSAGE); } } } catch (Exception e1) { // TODO Auto-generated catch block e1.printStackTrace(); }finally { linkdatabase.closeAll(rs, ps, con); } } if(source == b2) { System.exit(0); } }}
    4 系统测试以及界面4.1 订书单位信息查询测试测试注册账号,界面如图4.1所示。

    注册账号成功,结果如图4.2所示。

    4.2 病人出院结算测试进入病人出院结算界面,点击查询与结算,得出病人出院费用,结果如图4.3所示。

    结算出院成功,结果如图4.4所示。

    5 总结在本次数据库课程设计中,我设计开发了一个小型的医院病房管理系统,实现了对病人的住院登记、出院结算、信息查询,对医生信息、病人信息、科室信息、病房信息、病床信息的增加、删除、修改、查询的功能。设计过程中曾经遇到了不少难点和问题,如:将界面和后台数据库连接起来时出错;对数据库中信息操作时有时忽略了参照完整性;病人出院结算时无法调用数据库中存储的信息;页面间参数传递实现不了;还出现了一个语法错误,对一些控件的属性及方法不熟悉等。对于上述这些难点,我花了很多时间去解决,查阅数据库教材和理论课的课件、并借来相关书籍辅助学习,注意数据库中各个所建表的主外键约束,上网搜索也让我学到很多知识,还有些问题是与同学之间的相互讨论,最终将难点一一克服。
    3 评论 156 下载 2018-11-06 15:43:53 下载需要5点积分
  • 基于C语言的串模式匹配算法

    一、实验要求1.1 实现功能从主串中第K个字符起,求出子串在主串中首次出现的位置,即模式匹配或串匹配。
    要求用三种模式匹配算法分别实现:

    朴素的模式匹配算法(BF算法)
    KMP改进算法(Next[ ])
    KMP改进算法(NextVal[ ])

    1.2 设计要求首先设计一个含有多个菜单项的主控菜单程序,然后再为这些菜单项配上相应的功能。
    程序运行后,给出5个菜单项的内容和输入提示:

    1.输入主串、子串和匹配起始位置
    2.朴素的模式匹配算法
    3.KMP改进算法(Next[ ])
    4.KMP改进算法(NextVal[ ])
    0.退出管理系统

    请选择0—4:

    菜单设计要求:使用数字0—4来选择菜单项,其它输入则不起作用
    输出结果要求:输出各趟匹配详细过程(其中3、4,首先输出Next[ ]或者NextVal[ ]的各元素的数值),然后输出匹配总趟数、单个字符比较次数、匹配成功时的位置序号或者匹配失败提示信息

    二、实验步骤2.1 程序流程图2.1.1 主函数流程图
    2.1.2 Input函数流程图
    2.1.3 Output函数流程图
    2.1.4 getNext_val函数流程图
    2.1.5 Index_BF函数流程图
    2.1.6 Index_Next函数流程图
    2.1.7 Index_NextVal函数流程图
    2.1.8 getNext函数流程图
    2.2 主函数源码#include <stdio.h>#include <string.h>#include <stdlib.h>void Input(char* str1, char* str2, int* pos); //输入主串、模式串、匹配位置的函数void Index_BF(char* str1, char* str2, int pos); //朴素的匹配算法void Index_Next(char* str1, char* str2, int pos); //KMP算法void Index_NextVal(char* str1, char* str2, int pos); //KMP改进算法(NextVal[])void Output(char* str); //输出主串或模式串void getNext(char *str1, int* &next); //计算next数组的值void getNext_val(char* str2, int* &nextval);void main(){ int choice; char str1[1000]; char str2[100]; int pos; while(1) { printf("请选择功能:\n"); printf("1.输入主串、子串和匹配起始位置\n"); printf("2.朴素的模式匹配算法\n"); printf("3.KMP改进算法(Next[])\n"); printf("4.KMP改进算法(NextVal[])\n"); printf("0.退出管理系统\n"); scanf("%d", &choice); switch(choice) { case 1: Input(str1, str2, &pos); break; case 2: Index_BF(str1, str2, pos); break; case 3: Index_Next(str1, str2, pos); break; case 4: Index_NextVal(str1, str2, pos); break; case 0: return; default: printf("输入数字错误\n"); } }}
    2.3 运行结果截图2.3.1 主函数运行结果
    2.3.2 Input函数运行结果
    2.3.3 Index_BF函数运行结果
    2.3.4 Index_Next函数运行结果
    2.3.5 Index_NextVal函数运行结果
    三、总结与体会在该实验中,我实现了几种模式匹配算法,并通过程序输出匹配的过程,让我对课本上的理论知识有了更深层次的理解。
    这些程序还有些不完美的地方,可能有些算法实现地比较复杂,有些地方写出来之后不具有普遍性,只针对某种特殊情况。这些不完美的地方在之后我还会尽量修改。
    1 评论 2 下载 2019-09-29 07:20:02 下载需要6点积分
  • 基于C语言的单链表客房管理系统

    一、实验内容1.1 实现功能以带表头结点的单链表为存储结构,实现如下客房管理的设计要求。
    1.2 设计要求#include<stdio.h>#include<stdlib.h>#include<string.h>//定义客房链表结点结构typedef struct HNode{ char roomN[7]; //客房名称 float Price; //标准价格 float PriceL; //入住价格(默认值=标准价格*80%) int Beds; //床位数Beds char State[5]; //入住状态(值域:"空闲"、"入住"、"预订",默认值为"空闲") struct HNode *next; //指针域}Hotel, *HLink;

    实现创建客房信息链表函数void Build(HLink &H),输入(客房名称、标准价格、床位数),同时修改入住价格、入住状态为默认值,即入住价格=标准价格*80%,入住状态为”空闲”(提示:用strcpy()字符串拷贝函数)。为了提高程序调试效率,强烈建议:用文件操作来输入客房信息(客房名称、标准价格、床位数)
    实现输出客房信息函数void Exp(HLink H),输出所有客房的客房名称、标准价格、入住价格、床位数、入住状态
    函数int Find(HLink &H, char *roomN)),查找房间名称为roomN的客房。如果找到,则返回该客房在链表中的位置序号(>=1),否则返回0。提示:用strcmp()字符串比较函数
    实现函数void updateH(HLink &H, int beds, char *state),将床位数为beds的客房入住状态改为state。提示:用strcpy()字符串拷贝函数
    函数void Add(HLink &H),将该链表中未入住的客房入住价格均加价20%
    求出入住价格最高的客房函数HLink FirstH(HLink &H),该函数内return语句返回入住价格最高的客房结点指针,返回前将该结点在链表中删除
    函数void MoveK1(HLink &H, int k),将单链表中倒数第k个结点移到第一个结点位置,注意:严禁采用先计算链表长度n再减k(即n-k)的方法
    函数void ReverseN2(HLink &H),将单链表的正中间位置结点之后的全部结点倒置的功能,注意:严禁采用先计算链表长度n再除以2(即n/2)的方法
    函数void SortPriceL(HLink &H),按照客房(入住价格,客房名称)升序排序
    函数void upBed(HLink &H,int beds),创建一个【床位数为beds的新结点】(还需输入:客房名称、标准价格等信息),使链表的形态为:【头结点】->【床位数>beds的结点】->【床位数为beds的新结点】->【床位数<=beds的结点】,要求【超过beds的结点】和【不超过beds的结点】这两段链表中的结点保持原来的前后相对顺序
    主函数main()调用以上函数,(3)若返回值>=1则输出该客房在链表中的位置序号,否则输出该客房不存在;输出(4)~(10)处理后的链表内容,其中(6)还要输出入住价格最高的客房信息

    可能用到的函数:

    从文件中读取客房数据:fscanf(文件指针,”%s %f,%d”,p->roomN,&p->Price,&p->Beds);
    输出客房数据:printf(“%s%8.1f%8.1f%6d%8s\n”,p->roomN,p->Price,p->PriceL,p->Beds,p->State);
    字符串赋值函数:char* strcpy(char *, const char *);
    字符串比较函数:int strcmp(const char *, const char *)

    二、实验步骤按以上实验内容的要求,给出实验步骤,包括程序流程图、源程序和运行结果截图等。
    2.1 函数流程图2.1.1 主函数流程图
    2.1.2 Build函数流程图
    2.1.3 Exp函数流程图
    2.1.4 Find函数流程图
    2.1.5 updateH函数流程图
    2.1.6 Add函数流程图
    2.1.7 FirstH函数流程图
    2.1.8 MoveK1函数流程图
    2.1.9 ReverseN2函数流程图
    2.1.10 SortPriceL函数流程图
    2.1.11 upBed函数流程图
    2.2 main函数源代码void main(){ HLink H; int choice; Build(H); while (1) { printf("请选择使用的功能:\n"); printf("1.输出全部客房信息\t\t\t\t2.查找客房名称\n"); printf("3.更改指定床位数的客房的入住状态\t\t4.未入住的客房加价20%%\n"); printf("5.找到价格最高的客房\t\t\t\t6.倒数第k间房移动到第一间的位置\n"); printf("7.正中间客房之后的房间全部倒置\t\t\t8.按照客房(入住价格,客房名称)升序排序\n"); printf("9.创建新客房\n"); scanf("%d", &choice); switch (choice) { case 1: Exp(H); break; case 2: { printf("请输入要查找的客房名称:"); char name[7]; scanf("%s", name); int pos = Find(H, name); printf("客房名称为%s的房间在第%d个位置:", name, pos); break; } case 3: printf("请输入要更改的客房的房间数:"); int bed; scanf("%d", &bed); printf("请输入要更改的状态\n"); char state[5]; scanf("%s", state); updateH(H, bed, state); break; case 4: Add(H); break; case 5: { HLink high = FirstH(H); break; } case 6: printf("请输入要移动的客房位置:"); int k; scanf("%d", &k); MoveK1(H, k); break; case 7: ReverseN2(H); break; case 8: SortPriceL(H); break; case 9: printf("请输入新客房房间数:"); int beds; scanf("%d", &beds); upBed(H, beds); break; default: printf("输入不合法\n"); } printf("\n\n\n"); }}
    2.3 运行结果截图2.3.1 main函数执行结果
    2.3.2 Exp函数执行结果
    2.3.3 Find函数执行结果
    2.3.4 updataH函数执行结果
    2.3.5 FirstH函数执行结果
    2.3.6 MoveK1函数执行结果
    2.3.7 ReverseN2函数执行结果
    2.3.8 sortPrice函数执行结果
    2.3.9 upBed函数执行结果
    三、总结与体会通过这些实验题目,让我感受到理论知识和实际应用还是有一些区别,在学习数据结构的过程中,光学习理论知识是不够的,更重要的是自己动手实践,这样才能更好的理解知识并学会运用。
    该实验使我对链表有了更好的理解,明白了链表几种基本操作的实现方法,知道了什么时候该用到链表这种结构。我也遇到了一些困难。比如链表操作时使用了NULL指针中的内容;模式匹配不知道如何直观输出匹配过程,不会记录匹配次数。
    1 评论 1 下载 2019-09-27 07:18:27 下载需要6点积分
  • 基于PHP和MySql的学生成绩管理系统

    摘 要随着学校向全国及至世界范围的持续扩张,学生人数的增加,对于学生的信 息管理也越来越复杂,要求也越来越高,因此需要一个全面、详细的信息管理系 统,以便完成对学生信息的管理。无纸化的环境是技术时代的一个梦想,也是许 多学校和公司越来越意识到的一个真实世界。以前是由学生档案和公告栏来提供 各种信息及通告新的变化,而现在这个繁杂的工作已被网站和内部计算机网络所 取代。使得学生信息的管理更方便、安全。 根据调查得知,现在广大学生进行信息提交的主要方式是基于文件、表格等 纸介质的手工处理,学生信息管理部门信息处理工作量大,容易出错,且管理方 面因人而异。然而学校网上学生信息管理系统应该覆盖各个所需功能,使各级管 理人员和广大教职工在信息系统的辅助下进行工作,提高管理的整体水平。使得 学生信息管理更方便。 学生信息管理系统,可以用集中的数据库将与人力资源管理相关的信息全 面、有机地联系起来,有效地减少了信息更新和查找中的重复劳动,保证了信息 的相容性,从而大大地提高了工作效率,还能使原来不可能提供的分析报告成了 可能。在采用和实施学生信息管理系统之后,就会将依赖于人的过程改为依赖于 计算机系统的过程。学校管理人员只要获取了相应的权限,就可以随时进入系统, 直接查阅相应的信息。采用和实施学生信息管理系统不仅仅是为了提高工作效 率。为了除掉手工记录的低效率工作方式,运用信息化管理,提高工作效率,开 发本系统。 应该看到,在实施学生信息管理系统后,经过整合的、较为全面、准确、一 致和相容的信息不仅可以让学校领导对本学校学生资源的现状有一个比较全面 和准确的认识,同时也可以生成综合的分析报表供学校领导人在决策时参考。
    1 绪论1.1 课题简介随着时代的发展,成绩管理 成了每个教育部门不可或缺的一部分,它的内容对于学校 的有效管理显得尤为重要,作为计算机的一部分,用计算机进行成绩管理无疑会把这个过程 变得尤为简单。 学生管理系统为学生提供了简易的操作和方便的查询,以及更好的被管理。
    1.2 系统背景随着社会信息量的与日俱增,学校需要有一个学生成绩管理系统,以方便对学生的成绩 进行有效的管理。学生成绩管理系统是一个学校不可缺少的重要部分,它的内容对于学校的 决策者和管理者来说都至关重要,所以学生成绩管理系统应该为用户提供充足的信息和快捷 的查询手段。当前成教学院没有一个完善的成绩信息管理平台,计算机使用主要基于 Microsoft Office,不能发挥有效的作用。而且随着我国教育改革的不断深入以及自学教育 的不断扩招,参加考试的人越来越多,考试科目的多样化,使得成教学院对自学考试成绩的 管理越趋繁琐、复杂,工作业务繁杂,工作量大,这种传统的学生管理模式已经暴露出种种 弊端:难以统一调配和处理,效率极低,缺乏科学性以及合理性。随着计算机应用的普及与 深入,利用计算机能够对所有自学考试成绩进行统一管理,并进行分析,大大减少教学秘书 的工作量,提高工作效率,为教学办公带来了极大的方便。通过操作手册,使用者可以了解 本软件的基本工作原理及使用说明。操作人员只需输入一些简单的汉字、数字,就可以存储、 查找、修改、打印学生成绩信息等。本系统开发的总体任务是实现学生成绩管理的系统化、 规范化、自动化、达到提高学生成绩管理效率的目的,本系统本着实用性、通用、开放和安 全的原则,使数据库开发软件开发制作,实现了学生信息管理、课程信息管理、学生成绩管 理、成绩查询等功能。该设计方法易于推广至其它信息化管理系统的设计,充分利用计算机 作为辅助工具,实现学生考试成绩从传统的手工管理到计算机管理,对提高管理效率和节约 大量的人力、物力有一定的推动作用。本系统一切从实际出发,充分考虑了成绩的内部管理、信息交流等方面的复杂需求,实现成绩的有效管理,真正为学生成绩管理提供一个电子平台。 合理的数据库结构设计可以提高数据存储的效率,保证数据的完整性和一致性。同时,合理 的数据库结构也有利于程序的实现。
    1.3 系统开发运行环境
    操作系统:win10
    软件:AppServ(php+apache+mysql),nginx(代理)

    2 需求分析2.1 系统需求当今社会,计算机的使用已经深入到日常生活和工作的方方面面,它逐渐成 为人们学习和工作时必不可少的工具。虽然目前为止已经开发出了成千上万的软 件系统,但它们并不能满足用户的各种特殊需要,因此人们不得不开发属于自己 的软件,能够满足自己的特殊需求。学生管理系统是教育事业单位必不可少的。 它的内容对学校的管理者来说至关重要,学生成绩管理系统应该能够提供快捷的 查询功能以及能够及时修改、增添、删除信息等功能。传统的人工管理文件档案 的方式存在很多缺点,例如:效率低、保密性差、另外时间一长,信息量的不断 扩增,都给查找、更新何维护带来很大困难。使用计算机对学生成绩进行管理, 具有手工管理不可比拟的优点。例如:检索迅速、查找方便、存储信息量大、保 密性好、及时更新并进行维护等。计算机管理学生成绩能够提高学校的管理效率, 是科学化、正规化管理的重要途径,型心计算机管理将不断深入到学校的各项事 务的管理当中。
    2.2 功能要求2.2.1 教职工对学生成绩有一个整体的了解,在今后的教学中能有所改进。同时可 以对自己教授的课程进行修改,进一步了解学生的个人情况,便于因材施教。 当学生的个人信息发生改变时,老师能够及时进行修改。例如学生转校、后来转 到本系、或者毕业生离开学校等,老师能够根据具体情况对学生信息进行添加、 修改、删除等。能够管理课程信息,合理安排老师教授的课程,及时为学生提供 选课信息。老师能够对课程名、课程编号、学分等进行修改和更新。能够对学生 成绩进行发布、修改、删除,清晰地了解学生的成绩情况,以便做出总结和改进。
    2.2.2 学生能够查询个人的学习成绩和总体学生的成绩,以便做出新的定位。

    成绩查询:成绩修改、成绩添加、成绩删除等
    课程查询:课程修改、课程添加、课程删除等
    学生查询:学生信息修改、学生信息添加、学生信息删除等

    2.3 可行性分析为了使系统在学院的管理中发挥更大的作用,实现工作过程的计算机化,提高工作效率 和工作质量,现提出如下的系统开发目标:

    提供了成绩查询的平台,可以用来发布成绩
    任何学生都能上去查看自己的成绩
    学生可以凭借自己的学号进行查询
    管理员可以进行数据的添加

    可行性研究的目的是用最小的代价在尽可能短的时间内确定问题是否能够解决。也就是说 可行性研究的目的不是解决问题,而是确定问题是否值得去解,研究在当前的具体条件下, 开发新系统是否具备必要的资源和其它条件。
    2.3.1 经济可行性主要从对项目的经济上进行分析评价,一方面是支出的费用,包括设备购置费、管理 和维护费用、人员工资和培训费等,另一个是取得的收益。这是个超小型的管理系统,从投 入的人力,财力与物力来讲是非常之小的,只要一台电脑,一台打印机,这个系统就可以搞 起来,考虑到学校里有电脑,现只要购置一台打印机就可以了。从节省人力方面,可以让管 理人员从繁与复杂的工作中解脱出来,做更多的工作,可以给教学管理提高一个层次。
    2.3.2 管理性学生成绩管理系统是对学生成绩进行管理的一个简单系统,主要又成绩的输入、输出、 浏览、打印、数据备份等组合而成,因此可适用于任何学校用作成绩管理。该系统管理方法 科学,相应的管理制度成熟,所记录的原始数据准确,且操作简单、快速,对管理人员的计算级应用技术要求不高,可被一般管理人员所接受,所以在管理上具备一定的可行性,便与普遍采用。
    2.3.3 技术性在开发本应用软件时,我是按照软件周期进行开发的。而我所设计的学生成绩管理系统 是一个用php 和 Mysql 加前端js框架实现的前后端分离开发的应用系统。
    2.4 安全与完整性要求建立数据库用户,对其权限进行设置。确定各表主键、索引、参照完整性、 用户定义完整性。
    2.5 数据字典学生表(学号,姓名,性别,系别,学生年龄)
    课程表(课程号,课程名,课时,学分)
    成绩表(课程号,学生号,成绩。)
    老师表(老师姓名,老师编号,所授课程,联系电话)

    名字:老师信息描述:学生成绩管理系统中存储的所有老师的信息定义:老师信息=老师姓名+所授课程+教师编号+联系电话
    名字:学生信息描述:学生成绩管理中存储的所有学生信息定义:学生信息=学生学号+学生姓名+学生性别+学生系别+学生年龄位置:存储 输出供查询
    名字:课程信息描述:多个必要课程信息组成定义:课程信息=课程号+课程名+课时+学分位置:存储 输出供查询
    名字:用户表信息描述:用户个人的信息定义:用户信息=用户名位置:存储 输出供查询
    名字:学生成绩信息输入:学生姓名输出:相应的学生成绩信息
    名字:查询信息描述:用户提出的具体查询请求定义:查询信息=[课程查询信息]+[学生查询信息]位置:课程表 学生表 成绩表
    名字:添加信息输入:学号、学生姓名、学生性别、系别、学生年龄输出:新输入的学生信息
    名字:删除信息输入:选中所要删除的学生信息输出:删除完成系统的实体与联系

    3 概念结构设计3.1 系统与实体的联系由需求分析的结果可知,本系统设计的实体包括:

    学生基本信息:学号,姓名,学院,班级,年龄,性别
    课程基本信息:课程名,课程号,学时
    教师基本信息:教师号,教师姓名,职称,年龄,性别,学院
    学院基本信息:学院名、学院号、院长姓名

    这些实体间的联系包括:

    每位学生可以学习多门课程,每门课程可供多位学生学习
    每门课可以由多个老师教,每个老师可以教多门课程
    学生每选一门课就可以得到一个成绩,不选此课就不能取得该课程成绩

    3.2 各个实体 E-R 图3.2.1 学生表
    3.2.2 教师表
    3.2.3 课程表
    3.2.4 成绩表
    3.2.5 总体实体练习图
    3.3 E-R图转实为关系模型3.3.1 学生表


    属性名
    数据描述
    数据类型
    是否为空
    备注




    sno
    学号
    Char(8)
    不允许为空
    主键


    sname
    姓名
    Char(10)
    不允许为空



    Ssex
    性别
    Char(2)
    不允许为空



    Ssex
    性别
    C har(2)
    不允许为空



    sbirth
    出生日期
    atetime(8)
    允许为空



    class
    所在班级
    Char(4)
    不允许为空



    type

    Char(7)
    允许为空



    3.3.2 教师表


    属性名
    数据描述
    数据类型
    是否为空
    备注




    tno
    教师编号
    char(5)
    不允许为空
    主键


    tname
    姓名
    varchar(10)
    不允许为空



    depart
    部门
    varchar(8)
    不允许为空



    Tsex
    性别
    char(2)
    不允许为空



    Tbirth
    出生日期
    datetime ,
    允许为空



    prof
    职称
    char(6)
    允许为空



    3.3.3 课程表


    属性名
    数据描述
    数据类型
    是否为空
    备注




    cno
    课程号
    Char(5)
    不允许为空
    主键



    cname
    课程名称
    varchar(10)
    不允许为空


    tno
    教师编号
    char(3)
    不允许为空



    3.3.4 成绩表


    属性名
    数据描述
    数据类型
    是否为空
    备注




    sno
    学号
    Char(8)
    不允许为空
    主键


    cno
    课程号
    Char(5)
    不允许为空
    主键


    degree
    成绩
    Float(8)
    不允许为空



    5 物理结构设计4.1 确定关系模型的存取方法在将概念模型转换成物理模型之后,我们可以对物理模型进行设计,双击 物理模型的关系,可以对该关系的名称、注释等信息进行查询。可对该关系的属 性列进行设计,可分别设置其名称、码、数据类型以及主码、是否为空等。在实 际设计中最常用的存取方法是索引发,使用索引可以大大减少数据的查询时间, 在建立索引时应遵循:在经常需要搜索的列上建立索引; 在主关键字上建立 索引;在经常用于连接的列上建立索引,即在外键上建立索引;在经常需要根据 范围进行搜索的列上创建索引,因为索引已经排序,其指定的范围是连续的等规 则。才能充分利用索引的作用避免因索引引起的负面作用。
    4.2 数据流图该数据流图主要体现教职工对学生信息、课程信息和学生成绩的管理,然后 存储的信息作用于查询系统。在学生能够操作的只有成绩查询,如图所示:

    5 效果图5.1 登录5.1.1 学生
    5.1.2 教师
    5.1.3 管理员
    5.2.学生界面5.2.1 首页
    5.2.2 个人信息
    5.2.3 成绩查询默认当前学期

    选择学期

    5.2.4 本学期课表
    5.3 教师界面5.3.1 欢迎界面
    5.3.2 查询教授的课程
    5.3.3 录入成绩
    5.3.4 已录警告
    5.3.5 录入
    5.3.6 选择查看教授的课程已录入的成绩
    5.4 管理员界面5.4.1 学生管理界面查询所有

    分类模糊查询

    添加学生

    编辑信息

    删除学生

    5.4.2 教师管理查询所有

    分类模糊查询

    添加教师

    编辑信息

    删除学生

    5.4.3 课程管理
    5.4.4 排课管理
    5.5 其他5.5.1 退出登录
    5.5.2 修改密码
    6 主要代码6.1 database.php<?phpreturn [ // 数据库类型 'type' => 'mysql', // 服务器地址 'hostname' => '127.0.0.1', // 数据库名 'database' => 'grademanager', // 用户名 'username' => 'root', // 密码 'password' => '123456', // 端口 'hostport' => '3306', // 连接dsn 'dsn' => '', // 数据库连接参数 'params' => [], // 数据库编码默认采用utf8 'charset' => 'utf8', // 数据库表前缀 'prefix' => '', // 数据库调试模式 'debug' => true, // 数据库部署方式:0 集中式(单一服务器),1 分布式(主从服务器) 'deploy' => 0, // 数据库读写是否分离 主从式有效 'rw_separate' => false, // 读写分离后 主服务器数量 'master_num' => 1, // 指定从服务器序号 'slave_no' => '', // 是否严格检查字段是否存在 'fields_strict' => true, // 数据集返回类型 'resultset_type' => 'array', // 自动写入时间戳字段 'auto_timestamp' => false, // 时间字段取出后的默认时间格式 'datetime_format' => 'Y-m-d H:i:s', // 是否需要进行SQL性能分析 'sql_explain' => false,];
    6.2 登录代码 // 登录 public function login() { $t = model('CommonResData'); if (input('post.username') && input('post.password')) { $username = input('post.username'); $password = input('post.password'); $identity = input('post.identity'); if ($identity == 0) { $t->data = Db::query("select admin_name from admin where admin_id=$username and admin_password='$password'"); if ($t->data) { $t->code = 0; $t->data = $t->data[0]['admin_name']; // return JSON($t->resData($t->code,$t->data)); } else { $t->code = 3; $t->data = '没有该用户或密码错误'; } } else if ($identity == 1) { $t->data = Db::query("select teacher_name from teacher where teacher_id=$username and teacher_password='$password'"); if ($t->data) { $t->code = 0; $t->data = $t->data[0]['teacher_name']; // return JSON($t->resData($t->code,$t->data)); } else { $t->code = 3; $t->data = '没有该用户或密码错误'; } } else if ($identity == 2) { $t->data = Db::query("select student_name from student where student_id = $username and student_password='$password'"); if ($t->data) { $t->code = 0; $t->data = $t->data[0]['student_name']; } else { $t->code = 3; $t->data = '没有该用户或密码错误'; } } else { $t->code = 2; $t->data = '登录失败'; } Session::set('islogin',$username); Session::set('identity',$identity); return JSON($t->resData($t->code,$t->data)); } else { $t->code = 2; $t->data = "用户名密码不能为空"; return JSON($t->resData($t->code,$t->data)); }}
    6.3 判断是否登录 public function isLogin() { $isLogin = Session::get('islogin'); $t = model('CommonResData'); if (!$isLogin) { $t->code = 1; $t->data = '未登录'; return; } else { $t->code = 0; session('islogin', $isLogin); } }
    7 总结在此次的学生成绩管理系统程序设计的过程中,我充分认识到了做计划的重要性,只要实现把整体方案规划好,才能保证以后设计的顺利进行,才能应对出现的突发事件,达到系统设计的目标。在开始进行系统设计时,我对管理信息系统的认识比较少,对系统的开发 缺乏本质和深入地研究调查,以至与在着手设计的过程中,困难接踵而至。然而又不知道怎样解决,直到后来重新对此次的设计做了认真细致的规划调查,最终才使整个程序的设计工作完成,当爱系统还是有很多不足。然而,本次程序设计的收获不仅仅让我了解了 php与 appServ,使我对系统开发有了初步的了解,提高了编写程序的兴趣,如果今后有机会的话,我希望能够对编程有更深入的学习。
    1 评论 4 下载 2019-09-25 12:59:23 下载需要15点积分
  • 基于python的贪吃蛇游戏

    1、项目简介本项目为贪吃蛇游戏及自动寻路算法的实现。本项目分为两个小部分。
    1.1 贪吃蛇游戏本项目实现了带有 UI 界面的贪吃蛇游戏。玩家可以通过键盘操控贪吃蛇(蛇身黑、蛇头红),追逐随机产生的水果(绿)。
    在贪吃蛇游戏中,贪吃蛇会在一个二维平面(称为地图)上运动。每一轮,玩家控制贪吃蛇向前一个单位,向左一个单位或向右一个单位(不允许静止不动)。若贪吃蛇碰撞到地图的边界或自己的身体,则游戏失败。若贪吃蛇的蛇头触碰到水果,则蛇身延长一个单位。当蛇身能完全占满整个地图后,游戏胜利。

    1.2 自动寻路算法自动寻路算法为贪吃蛇赋予一定的智能,让其能正确地完成游戏。此处的 ‘‘正确’’ 有两层含义。

    当贪吃蛇能触碰水果时,其应主动沿较优路接近水果
    任何时候,当下一步行动可能造成贪吃蛇的死亡时,贪吃蛇应避免该行动目前实现自动寻路的方法有很多,例如:

    朴素贪心算法保守 Hamilton 回路算法改良 Hamilton 回路算法 遗传算法改良的贪心算法

    这些方法会在节7作详细描述。其中本项目使用的是改良的贪心算法。
    NOTE:本项目使用的改良贪心算法,可以证明其正确性。它的效率和准确度都是所有算法中最高的。
    2、项目闪光点
    效果优良的寻路算法
    无向图最长路近似算法
    解耦的实现 TODO

    3、环境与运行3.1 运行环境介绍运行本项目代码需 Python3.5 及以上和 Pygame 组件库。一种参考的安装和运行方法见代码 1。
    在代码1中,需要预安装 python 虚拟环境管理工具 conda(并非必要),并使用 pip 安装 pygame 组件库。在安装完毕后,使用 cd 命令进入 code/目录,并直接运行 main.py 程序即可。
    $ conda create --name game python=3.7 2 $ pip install pygame $ cd code/ 4 $ python main.py
    3.2 运行方法和使用方法3.2.1 程序运行使用小节3.1介绍的方式(或其他等价方式)安装环境并运行 main.py 代码。以下假设程序已正常运行。
    3.2.2 配置文件本游戏给予玩家很大的可配置性,许多参数都存放在配置文件 (config.json) 中。这里提供了一份默认的配置文件(代码 2), 但用户可以随意按需修改。
    NOTE:在 main.py 文件的同一目录下,必须存在一份 config.json 文件,否则游戏因缺少参数而无法运行。
    在配置文件中,window-width 和 window-height 分别指定游戏窗口的大小。block-size 指定游戏中一个 ‘‘块’’ 的大小(贪吃蛇每次以块为单位移动)。块必须能整除 window-width 和 window-height。speed 是游戏速度,决定贪吃蛇的移动间隔时间(秒)。auto 指是否开启 AI 自动寻路。
    { "window-width": 800, "window-height": 600, "block-size": 50, "speed": 0.3, "auto": true }
    3.2.3 游戏键位使用 W,S,A,D 分别控制贪吃蛇向上、下、左、右运动。使用 U 和 I 控制游戏的速度,U 加快游戏速度, I 减慢游戏速度。使用 Q 退出游戏。
    (按下空格键以产生一份”output_<hash>.log” 文件,用于 debug)。
    4、代码文件介绍4.1 主文件 main.pymain.py 调用了其他所有的文件,是玩家直接运行的程序。
    该文件使用 Snake 类和 Fruit 类存储了地图信息,使用 Pygame 绘制了游戏窗口,使用 SnakeDrawer 和 FruitDrawer 为不断变化的 snake 和 fruit 更新绘制图像。同时,Pygame 还负责监听键盘事件,响应玩家的操控。main.py 还负责使用延时来处理游戏速度。
    4.2 游戏类 snake.py 和 fruit.pySnake 类和 Fruit 类分别定义在 snake.py 和 fruit.py 上。
    Snake 类存储了贪吃蛇的内部状态,例如所有蛇身所在的坐标(特别地,蛇头看做第一段蛇身),蛇的当前方位等。Snake 类暴露了若干接口,用于设置蛇的当前走向、控制蛇向前一步,检验蛇是否处于非法状态等。
    Fruit 类存储了水果的内部状态,例如水果的当前坐标。Fruit 类还实现了 generate 函数,产生下一个 水果的出现位置。由于水果不能出现在蛇身占用的格子上,故 Fruit 的 generate 函数可能会被反复调用,直到得到的结果符合游戏要求。
    4.3 寻路类 pather.py 和 solver.pypather.py 是寻路类的主要模块,其中的类 PathSolve 是辅助工具,用于求出蛇头距离水果的最短路,以及蛇头距离水果和蛇尾的最长路。
    NOTE: 无向图中的两点最长路是 NP-Hard 问题,但本项目使用了近似算法,在小规模数据中取得了等价于精确解的效果。
    PathSolve 使用了广度优先搜索算法得到最短路。可以容易地将其拓展为 A-Star 算法获得更好的性能。但广搜的性能在此处已经足够好。同时,其采用了‘‘最短路拓展”的方法找到近似最长路,具体地说,它在最短路的基础上反复尝试将路拓展延长 2 个单位,直到无法进行任何的拓展为止。更详细的介绍见节 6。
    solver.py 定义了 GredySolver 类。如名字所见,该类采用改良的贪心算法进行寻路。当蛇可以轻易吃到水果时,蛇会优先以最短路走向水果,否则,蛇会以最长路走向蛇尾。更详细的介绍见节 6。
    5、贪吃蛇游戏的具体实现5.1 常亮定义在贪吃蛇项目中,定义以下的若干常量可以简化代码的书写,使得代码的可读性更好。

    5.2 Snake 类的具体实现Snake 类定义了一系列接口。它们大致可以分为返回状态的接口和更新状态的接口。
    返回状态的接口包括 head, tail, direction, nextHead, valid, at 等。
    nextHead是必要的,这是因为如果蛇下一步前进时会触碰到水果,新的水果必须在同一时刻出现在地图上。知道蛇头下一刻处于的位置是有好处的。
    at 用于判断地图上的某个方块是否被蛇身占用。在生成水果时会用到。水果必须生成在不被蛇身占用 的方块上。
    有副作用的函数包括 next, eatFruit 等。其中调用 next 后会使得蛇前进一个块。Snake 类中存储了蛇身的坐标以及蛇头方向。在调用 next 后,蛇头向前延伸一个单位,并把延伸的块的坐标插入到蛇身的第一个元素(.insert(0, *))。还要把蛇身的最后一个元素删除 (.pop())。
    eatFruit 被调用后,蛇的内部状态会记录着当前吃到了一个水果 (hasEat = True); 在下一次 next 被调用时,不再把蛇身的最后一个元素删除(相当于蛇身变长一个单位)。无论怎样,在调用 next 后都会把吃到水果的状态置空 (hasEat = False)。
    注意到许多函数是幂等的。幂等的意思是,这些函数连续调用一次以上的效果和只调用一次的结果是 一样的。例如连续多次 turn(RIGHT),或者多次调用 getHead。幂等的性质可以给编程带来极大的便捷。(此处留意,turn(RIGHT) 的 RIGHT 指的是绝对的右方,而不是指相对于蛇头的右方)。

    5.3 Fruit 类的具体实现由于 fruit 类的实现比较简单,故直接放上代码(代码 3)。
    __init__ 函数主要读取了 config 的信息,设置了 width 和 height 两个内部状态。
    函数 generate、where 和内部状态 last_generate 的设计是比较好的,我后续的许多代码都得益于这个接口而得到改进。
    首先 generate 函数显式地产生随机坐标,将随机坐标记录到 last_generate 上,并返回。fruit 类会一直维护着最后一次产生的随机坐标。事实上,这个 ‘‘最近一次的随机坐标对’’ 恰好就是游戏当前水果所在的地点。
    where 函数返回

    如果 last_generate 为空,则调用 generate 后,再返回 last_generate
    否则,直接返回 last_generate 这个设计使得用户可以安全地随时调用 where 函数,且确保 where 函数有合法的返回值。只有在当前的状态过期时(水果被吃掉了),才有必要调用 generate 函数重新生成水果

    NOTE: 最近一次产生的随机坐标,是当前游戏中水果的位置坐标。
    class Fruit: def __init__(self, config): self.config = config # some code to get width from ‘config‘ self.width = ... # some code to get height from ‘confgi‘ self.height = ... self.last_generate = None def generate(self): x = random.randint(0, self.width - 1) y = random.randint(0, self.height - 1) self.last_generate = (x, y) return (x, y) 14 def where(self): if self.last_generate is None: self.generate() return self.last_generate
    5.4 Drawer 和相关类的具体实现Drawer 相关的类有三个。分别是 Drawer, SnakeDrawer 和 FruitDrawer。其中 Drawer 类是后两个类的基类。
    5.4.1 Drawer 基类的实现Drawer 类定义了两个基本函数 (代码 4),分别是_basic_draw 和 _toLeftTop。下划线代表这两个成员函数是保护 (protected) 成员函数。
    这里的实现牵扯到一些 pygame 的使用细节,但大体的思路是很明确的。本项目中,水果、蛇身和蛇头都采用方块来表示。成员函数 _basic_draw 封装了画方块这一操作。
    self.rect 缓存了一个边长为 blk 的方块信息,其中 blk 是从配置文件中读取的内容。在实际画出方块时, 需要对 self.rect 作(以窗口左上角为原点的)平移操作。平移时只需要修改 self.rect 对象中的 topleft 属性即可。该属性是个 getter/setter 语法糖,在该属性被修改时,会触发 self.rect 修改其他相关属性 (例如 left, top 等),以维持方块的一致性。
    _basic_draw 函数首先对方块作平移,随后在 Surface 上画出这一方块。在函数 _basic_draw 中,Surpface 是对象 screen。screen 是代表整个窗口的 Surface,由 Drawer 类被构造时传入。
    _toLeftTop 接受坐标 x 和 y,返回 x 行 y 列的方块的 topleft 值。
    5.4.2 SnakeDrawer SnakeDrawer 的成员函数其中 __remove 和 __draw 函数调用了基类的函数 _basic_draw。函数 next 是有副作用的函数,它和 Snake 类的耦合度比较高。它的作用是,调用 Snake 函数的 next 方法,让蛇向前行走一步,并仅仅更新蛇头和蛇尾两个方块。这样的目的是加快程序的运行效率。绘制图形和刷新窗口是非常费时的操作,加快程序运行方法有两个层面。

    尽可能减少窗口的刷新范围
    尽可能较小窗口的刷新频率 SnakeDrawer 和 Snake 类在 next 方法上强耦合,但能 ‘‘减少窗口刷新范围’’

    SnakeDrawer 类还有一个 draw 成员函数,它的作用是画出全部的蛇身。在整个游戏窗口初始化时,这个函数会被调用。但随后,对 snake 的所有绘图都仅适用 next 函数。
    class Drawer(): def __init__(self, screen, config): self.blk = int(config[’block-size’]) self.rect = pygame.Rect(0, 0, self.blk, self.blk) self.screen = screen def _basic_draw(self, x, y, color): self.rect.topleft = self._toLeftTop(x, y) pygame.draw.rect(self.screen, color, self.rect) def _toLeftTop(self, x, y): return (x * self.blk, y * self.blk)

    5.5 FruitDrawer FruitDrawer 的定义该实现比较简单,故直接附上源码。它仅提供了 draw 接口,它调用了 Fruit 的 where 成员函数,画出水果的当前位置。
    6、自动寻路算法的具体实现本节介绍自动寻路算法的具体实现。它基于几个简单的搜索算法,在整体上使用贪心的思想。
    6.1 寻路算法介绍常用的寻路算法有许多种,以下详细见介绍。
    class FruitDrawer(Drawer): def __init__(self, screen, config, fruit): Drawer.__init__(self, screen, config) self.fruit = fruit self.width = int(int(config[’window-width’]) / config[’block-size’]) self.height = int(int(config[’window-height’]) / config[’block-size’]) def draw(self): x, y = self.fruit.where() self._basic_draw(x, y, GREEN)
    6.1.1 朴素贪心算法朴素贪心算法采用最朴素的贪心法。在每一步中,直接搜索从蛇头到水果的最短路,并按该条路线前往水果。
    该方法的优点是易于实现,思路简洁。但它的缺点也很明显。在贪吃蛇游戏中,局部最优解一般都不为全局最优解(且往往相差很远)。这不满足我们在??中提出的 ‘‘任意时刻贪吃蛇应避免死亡’’ 的要求。
    如果贪吃蛇按箭头方向根据最短路吃到了水果,它会因所有的出口都被堵住而游戏失败。
    很快可以看到,在朴素贪心算法的基础上添加 ‘‘无向图最长路近似算法’’,结合起来得到的改良版本可以获得很好的性能。

    6.1.2 保守的 Hamilton 回路算法朴素 Hamilton 回路算法的思路很简单。其尝试在地图上构造一条哈密顿回路,然后永远按照该回路在地图上无限循环地走。显然这个算法是绝对正确的,而且贪吃蛇绝对不会死亡。但这却不满足提出的‘‘沿较优路前往水果’’这个目标。
    除此之外,这个算法还有一个隐含的要求,就是地图需要包含一条哈密顿回路。事实上这点是无法确保的。对于不存在哈密顿回路的图,这个算法可能会失效。

    6.1.3 随机神经网络算法随机神经网络的方法是,使用纯随机(而非梯度下降)的方式优化参数。评价神经网络的标准也不再是交叉熵或准确度,而是 ‘‘贪吃蛇每局游戏的平均长度’’。
    具体来说,首先随机创建 n 个神经网络。每个神经网络的参数均来自独立的随机分布。神经网络的输 入是各种提前选定的属性,例如 ‘‘蛇头距离水果的距离’’,‘‘蛇头左侧是否有障碍’’ 等等。神经网络的输出是超参数,在整个模型训练中不变。神经网络的输出维度是 3,分别表示 ‘‘直行’’、‘‘左转’’ 和 ‘‘右转’’ 的自信度。
    使用这 n 个随机创建的神经网络玩贪吃蛇游戏,记录他们的平均蛇长。取出效果最好的 m 个神经网络 (m 一般比较小)。这为一轮训练。在这 m 个神经网络的基础上,加入随机的偏差,再次产生 n 个随机的神经网络。如此重复,直到最后的神经网络能取得比较好的效果。
    但这个算法有很大的缺点。例如 :

    需要人工选定输入的特征。难以选择合适的输入特征
    效果较差。目前大部分基于神经网络的算法都难以在贪吃蛇游戏中取得比较好的效果

    6.1.4 改良的贪心算法改良的贪心算法是本项目选择实现的算法,可以证明它不会使得贪吃蛇游戏失败,且在大部分情况下 沿最短路前往水果。它的主要思路如下。

    首先搜索一条蛇头到水果的最短路。然后假设贪吃蛇按照该最短路到达了水果。在此基础上,检查蛇 头是否有路径到达‘‘蛇尾’’。如果能到达蛇尾,说明蛇一定存在一个策略保证存活(称此状态为安全状态)。如果不能,则说明蛇在吃了水果后的处境可能会 ‘‘危险’’,于是拒绝这个决策,选择在周围游荡,以‘‘拖延时间’’。
    6.2 改良贪心算法的具体实现6.2.1 流程和正确性证明改良贪心算法的具体流程如下。为了寻找蛇 S1 的最佳方向 D

    (a) 构造从蛇 S1 到水果的最短路 P1。如果 P1 存在,则执行 (b)。否则执行 (d)
    (b) 构造一条虚拟的蛇 S2 ← S1,让 S2 前进并吃到水果
    (c) 构造蛇 P2 从蛇头到蛇尾的最长路 P2。如果 P2 存在,那么 D 就是 P1 的第一个方向。否则,执行 (d)
    (d) 计算蛇 S1 从蛇头到蛇尾的最长路 P3。如果 P3 存在,那么 D 就是 P3 的第一个方向。否则,执行 (e)
    (e)(worst case)D 为远离水果的那个方向

    对这个流程的相关解释如下:
    在计算从蛇头到水果的最短路后,还要判断蛇 S2 到其蛇尾是否具有最长路。这里要注意
    NOTE: 无向图的最长路算法是 NP-Hard 问题,此处使用了近似算法。在算法分析时,最坏情况可能退化到最短路。
    若蛇 S2 到蛇尾有最长路,可以得出蛇 S2 到蛇尾必有路(显然)。可知,这样的走法是安全的,这是因为。
    LEMMA: 当存在一条蛇头到蛇尾的路径时,贪吃蛇必不死。
    该引理是整个算法乃至整个项目最重要的一个理论基础。其奠定了改良贪心算法的准确性。
    要论证这个引理很简单。首先,蛇头是不可能 ‘‘追上’’ 蛇尾的,这是因为每当蛇头往前前进一步,蛇尾也会向前收缩一步。贪吃蛇只需要保证一刻不停地追逐蛇尾,就能保证必定不死。
    于是贪吃蛇存在一种策略:

    贪吃蛇按照从蛇头到蛇尾的路前进 该策略可以保证贪吃蛇必定不死
    这就证明了上述引理的正确性。这同时解释了步骤 (c) 的用意:保证蛇不死

    在不那么好的场景下,有可能出现以下的局面 :

    蛇 S1 不存在蛇头到水果的最短路 P1(步骤 a 的错误分支)
    蛇 S1 不存在从蛇头到蛇尾的最长路 P3(步骤 d 的错误分支)

    当 P1 不存在,说明了目前无法短时间内到达水果的位置。那蛇就应该尽可能地 ‘‘绕远路’’,争取拖延更多的时间。同时绕远路也应该绕得安全,那么这个远路就应该是从蛇头到蛇尾的远路。这就是 (a) 的错误分支跳转到 (d) 的解释。
    若 S1 不存在从蛇头到蛇尾的最长路,说明蛇在最坏情况下很可能已经进入了困境。算法中步骤 (e) 的方法是向原理水果的方向运动。这是最坏情况下的无奈之举。
    NOTE: 从蛇头到蛇尾的最长路必定存在。这是因为 (a) 在游戏开始时,存在从蛇头到蛇尾的最长路, 且 (b) 在游戏的每次 ‘‘状态转移’’ 时都保证蛇头到蛇尾的最长路存在。故实际上上一情况是不可能出现的。
    6.3 最长路算法6.3.1 算法思路最长路算法的基本步骤如下

    找到一条最短路
    尝试拓展最短路,直到无法拓展为止具体地说,在最短路 p 上定位相邻的两个结点

    对于这每组相邻的结点,尝试将他们从两个结点拓展到四个结点。例如相邻的结点 A 和 B 中,A 向左走一步可以到达 B([Left])。拓展时,尝试拓展 A 到 B 的路 [Down, Left, Up]。对称地,也可拓展为 [Up, Left, Down]。
    尝试画一下图显然得到,每次拓展都是把相邻的 2 个结点拓展成 4 个结点(类似于田字)。
    这个拓展算法显然不是精确解,但在绝大部分情况下却能取得几乎最优的效果。
    一系列图片是贪吃蛇沿着蛇头到蛇尾的最长路行进的示意图。图左一是贪吃蛇的初始状态。红方 块是蛇头,贪吃蛇(蜷缩)在一团。
    贪吃蛇很聪明地旋转着绕远路,同时留下一条空隙,给予自己回过头来回到蛇尾的机会。
    贪吃蛇绕远路达到了右边界,准备返回。
    贪吃蛇沿着左图一留下的 ‘‘空隙’’ 返回。逐步接近蛇尾。右图一中,贪吃蛇最终到达了蛇尾。
    这个最长路几乎是最优解,因为它的路径覆了整个地图,除了右上方的一个方块。


    6.4 算法实现最长路近似算法的算法实现如所示。代码仅展示重要部分。
    设变量 sp 存储的是最短路的走法中每一步的方向。算法一开始初始化 idx 为 0,cur 为最短路的第 idx 步的坐标。该算法反复尝试拓展第 idx 步,以求将第 idx 步拓展为 i0,i1,i2 三步。其中 i1 步就是第 idx 步, i0 和 i2 是额外拓展的两步,这两步走的是相反的方向(例如上和下,左和右)。如此一来, [i0,i1,i2] 三步的效果完全和 [idx] 步的效果一致。
    举个例子,例如最短路中第 idx 步是向上走的。拓展算法会尝试把 [UP] 拓展为 [LEFT, UP, RIGHT] (分别对应 i0,i1,i2)。可以看到,i1 等于第 idx 步的走向。 i0 和 i1 是两个相反的方向,且与第 idx 步垂直。
    以上的描述解释了代码6注释 (1) 处代码的作用。它使用 insert 方法,分别做 insert(idx,*) 和 insert(idx + 2, *),以完成以上描述中的拓展。
    NOTE: 在拓展之后,最短路的第 idx 步的方向发生了变化。但第 idx 步时所在的坐标不变。
    NOTE: 算法会在最短路的 0∼idx 段完全拓展完毕后,再自增 idx,尝试拓展 idx+1 段。
    def longest_path(self, target): ’’’ @variable sp最长路列表 ’’’ # idx如正文描述 idx = 0 # 最短路的第idx步时的蛇头位置 cur = self.snake.head() while True: extended = False direction = sp[idx] # 最短路的第idx步的走向 if direction in [’U’, ’D’]: test_extend = [’L’, ’R’] # 可能的拓展方向 else: assert(direction in [’L’, ’R’]) test_extend = [’U’, ’D’] # next_cur是cur沿着最短路走一步得到的结点 next_cur = self.pos_move(cur[0], cur[1], direction) for d in test_extend: # d是可能的拓展方向 # t1和t2分别是cur和next_cur朝着方向d移动一步得到的结点 t1 = self.pos_move(cur[0], cur[1], d) t2 = self.pos_move(next_cur[0], next_cur[1], d) # 如果t1和t2结点是能拓展的(该块在地图区域内且该块没有被占用) if self.__exstendable(*t1, game_map) and self.__exstendable(*t2, game_map): extended = True # (1) sp.insert(idx, d) sp.insert(idx + 2, self.rev_map[d]) # 将t1和t2的所在块设置为占用 x, y = t1 game_map[y][x] = ’X’ x, y = t2 game_map[y][x] = ’X’ break # 最短路从0到idx这一段已经完全无法拓展了。将idx加1 if not extended: cur = next_cur idx += 1 40 if idx >= len(sp): break return True, sp
    6.5 最短路算法本项目采用广度优先搜索算法寻找最短路。事实上,可以将该算法替换成 A Star 算法,获得更多性能的提升。
    7、效果评价贪吃蛇寻路算法的最终结果如图所示。
    其中红色方块是蛇头(右上角)。绿色方块是水果(中间)。黑色方块是蛇身。白色方块是蛇身未占领的区域。
    从图可以看到,贪吃蛇几乎占满了全部的地图区域。此时由于蛇没有处于图的哈密顿回路上,故蛇永远都无法吃到那个绿的水果。此时可以认为游戏结束,算法完美地完成了它的任务。
    2 评论 10 下载 2019-03-21 21:27:56 下载需要14点积分
  • 基于C#和SQL Server 2008的自助点餐系统设计与实现

    1.引言1.1 编写背景该项目开发的软件是饭店信息管理系统软件。随着人民的生活水品不断提高,生活也越来越好。就喜欢出去吃饭,酒店等人员来往爆炸性增长。饭店对自身和宾客信息的管理,越来越难。随着这方面的信息不断增长。人工的记忆管理的弊端越来越突显出来,自动化的管理,可以更好的。更方便、更有效的对饭店的日常的所有管理。增加工作效率。所以本系统就应运而生。本项目名称为饭店管理系统,系统就要与数据库交互。所以就要数据库,饭店管理系统的待开发的数据库名字为HotalMSDB。
    1.2 编写目的本文档是饭店管理系统设计文档的组成部分,编写此文档的目的是:明确此系统的需求和要具体实现什么功能,用来指导后期的数据库脚本的开发。本文档的读者对象是需求人员、系统设计人员、开发人员、测试人员。
    2.任务概述饭店管理系统的目标是尽可能的简化人工的操作,实现自动化。以最少的人实现最大的工作。尽量做到达到人力于设备费用的节省,并且使软件处理数据的速度提高,软件的整个设计过程必须通过生产能力的提高,人员工作效率的提高等等使软件开发成本最小化。实现保证软件质量的前提下的资金投入的最小化来获利益的最大化。本系统提供对员工的增删改,用户的增删改,菜的管理等饭店的基本日常管理。
    3.系统功能员工信息的增删该查,包括新老员工基本信息、工作信息、职位信息等。

    用户的增删该查,包括用户名和密码的更改
    饭店的菜种、菜的类型增删改查
    实现在店内的订餐点餐
    实现网络版的订餐
    实现在后台管理点餐订餐的功能
    订餐点餐的管理
    实现用户、员工、收银员的注册、删除等功能

    4.总体设计系统的流程图如下:
    4.1 客户点餐管理点餐
    4.2 员工的登录
    4.3 员工用户收入的操作流程图
    5.使用说明5.1 软件本系统编程工具是Microsoft Visual Studio 2010,数据库设计环境是SQL Server 2008系统。所以运行本系统的环境是Microsoft XP系统以上,必须安装了.net framework3.0以上的版本。
    5.2 硬件支持各种x86系列PC机 。
    6.系统流程6.1 系统总体流程
    6.2 订餐流程
    7.数据库设计7.1 表设计Users(用户表)



    字段名
    说明
    类型
    可空
    备注




    UserID
    用户ID
    int

    主键,自增


    userName
    用户名
    Nvarchar(10)

    唯一约束


    userPassword
    密码
    Nvarchar(20)




    userTypeID
    员工表的ID
    int

    外键-关联员工表主键



    Employees(员工表)



    字段名
    说明
    类型
    可空
    备注




    employeesID
    员工ID
    int

    主键,自增


    employeesName
    姓名
    Nvarchar(20)




    Sex
    性别
    Bit




    Age
    年龄
    int




    identityCard
    身份证号
    Nvarchar(18)




    Tel
    联系方式
    Nvarchar(11)




    userTypeID
    员工类型ID
    int

    外键-关联员工类型表的主键



    userTypes(员工类型表)



    字段名
    说明
    类型
    可空
    备注




    userTypeID
    ID
    int

    主键,自增


    userTypeName
    类型名
    Nvarchar(10)




    Accounts(收入表)



    字段名
    说明
    类型
    可空
    备注




    accountID
    收入ID
    int

    主键,自增


    Money
    收入金额
    Float




    bookdinnerID
    点餐表的id
    Int




    userID
    员工表的ID
    int

    外键-关联员工表主键


    times
    时间
    Datetime




    bookTypeID
    判断点出餐
    Int

    外键-关联点出餐类型表主键



    Foods(菜的种类)



    字段名
    说明
    类型
    可空
    备注




    foodID
    菜ID
    int

    主键,自增


    foodName
    某菜的名字
    Nvarchar(50)




    Price
    价格
    float




    Picture
    图片
    Image




    foodtypeID
    食物的类型id
    Int

    外键—关联食物表的主键


    number
    统计某菜的数量
    Int




    Foodtypes(食物表)



    字段名
    说明
    类型
    可空
    备注




    foodtypeID
    食物ID
    int

    主键,自增


    foodTypeName
    食物类型名
    Nvarchar(50)




    Books(订餐表)



    字段名
    说明
    类型
    可空
    备注




    bookID
    点餐ID
    int

    主键,自增


    booktime
    订餐时间
    Datatime




    eatTime
    订餐消费时间
    Datatime




    address
    订餐人的地址
    Nvarcahr(50)




    tel
    订餐人的联系方式
    Nvarchar(50)




    bookTypeID
    点出餐ID
    Int

    外键—关联点出餐表主键



    Launchs(出餐表)



    字段名
    说明
    类型
    可空
    备注




    launchID
    菜表的ID
    int

    主键—自增


    employeesID
    员工的ID
    int

    外建—关联员工表主键


    bookTypeID
    点出餐的ID
    int

    外键—关联点出餐表主键


    foodID
    食物ID
    Int

    外键—关联食物表主键


    time
    时间
    Datetime




    Chooses(点餐表)



    字段名
    说明
    类型
    可空
    备注




    Choose ID
    点餐的ID
    int

    主键,自增


    times
    点餐的时间
    Datatime

    自动获取


    sourceID
    桌子的编号
    Int

    外键—关联来源表主键


    bookTypeID
    点出餐的ID
    int

    外键—关联点出餐表主键



    Selectfooddetail(点餐详细表)



    字段名
    说明
    类型
    可空
    备注




    Selectfood ID
    点餐表的ID
    int

    外建—关联点餐表主键


    DishkindID
    菜表的ID
    int

    外建—关联菜表食物主键


    Selectfoodnumber
    数量
    int




    Source(来源表(点餐时的来源))



    字段名
    说明
    类型
    可空
    备注




    SourceID
    来源的ID
    int

    主键—自增


    Sourcenumber
    桌子来源的编号
    Nvarchar(10)




    BookTypes(点出餐类型表)



    字段名
    说明
    类型
    可空
    备注




    bookTypeID
    ID
    int

    主键—自增


    BookTypeName
    点出餐的类型
    Nvarchar(10)




    7.2 数据库关系图
    0 评论 3 下载 2019-09-24 15:39:27 下载需要10点积分
  • 基于MFC实现的基本门电路的绘制与连接

    一、设计内容本课题设计包括基本门电路非门和与门的绘制以及连线,以及位置拖动。具体采用的方法是在OnDraw里面遍历元器件绘制每一个元器件,根据元器件的选中与否采用不同的画笔绘制。
    二、方法与难点课题的难点有两个,一个是绘制,需要考虑对于不同的元器件,应该使用相同的接口类,实现绘制的统一性,并且引脚的绘制应该由不同的元器件对象自身完成。二是图像的刷新时的闪烁问题,在拖动连接线和元器件的时候刷新频率过快导致其他元件闪烁。解决方案有两个:
    一是使用最小矩形面积重绘的方法。对于元器件的移动,记录上一次的矩形外框位置和这一次的矩形外框位置,将两个矩形叠加得到一个最小的包含两个矩形的第三个矩形框(如图一),重新绘制该区域,即可最大限度减少无关图形的重绘;对于直线,确定一个以该直线为对角线的矩形(如图二),然后重绘该矩形。


    二是使用双缓冲缓冲绘图延时更新到屏幕解决闪烁问题。
    三、作品特色本作品的特点是有:界面简单美观,绘制闪烁问题的到极大改善,并且在拖动元器件的时候不会出现鼠标选择位置始终在左上角位置。
    四、项目类设计
    五、重点函数简介// 以下顺序不能更改 SingleGateSelect(point); // 根据点选中一个元器件if (lastSelectGate != NULL){ // 记录一个鼠标点击位置和元器件位置的偏移量 以解决鼠标在移动过程始终在左上角的问题 m_selectOffset = point - lastSelectGate->GetPosition(); }
    六、运行结果程序运行界面如下。界面简单整洁,包含与门与非门的添加按钮。拖动引脚连线。

    七、有待解决的问题
    连线只能是直线,不能自动转换为折线
    元器件不能旋转
    1 评论 1 下载 2019-09-23 09:50:18 下载需要12点积分
  • 基于Python实现的疲劳驾驶检测

    摘 要相比于完全把神经网络当成黑盒来做训练,本文尝试了一种混合的思路:先通过人脸特征点检测获得特征点,再通过特征点预估人脸位置、角度、眼睛开合度等参数,再通过一个LSTM网络进行参数的训练,并对视频做分类。
    一、相关工作2018年CES Asia展会上,科大讯飞展示了他们的驾驶员疲劳检测系统。他们的系统能通过计算机视觉的方法,从摄像头中获取人脸朝向、位置、瞳孔朝向、眼睛开合度、眨眼频率、瞳孔收缩率等数据,并通过这些数据,实时地计算出驾驶员的注意力集中程度。我在现场体验了他们的系统,非常灵敏准确。

    二、总体思路受到科大讯飞DEMO的影响,我做本期末报告时,也希望使用这种基于特征检测、参数计算的方法。我认为,这种方法不是完全黑盒的(相比于纯CNN网络来训练图片),在可解释性上可能会好一些,此外,这种方法还能够检测并记录别的体征数据,这些体征数据也有许多挖掘价值。
    我做的实验分为以下三步:

    通过图片特征点检测的方法获得人脸特征点(如眼、鼻、嘴、轮廓)这一步可以使用著名的dlib (King, 2018)来解决,有效果较好的已训练的模型:shape_predictor_68_face_landmarks.dat。使用它,可以得到68个人脸关键点。
    预处理,通过68个关键点判断人脸的朝向、位置、眼睛开合度信息判断人脸朝向和位置的主要难度在于估计人脸的三维信息,若有三维信息,就可以用OpenCV的函数solvePnP,来计算出一个物体的朝向和位置。但是,因为单目摄像机的深度信息是缺失的,不能真正得到3d数据,所以在解人脸朝向时,需要配合一些人体测量学的统计数据(鼻根到人脸各个器官之间的距离)才行。眼睛开合度的计算比较简单,因为已经有特征点数据,所以计算眼皮之间的高度,除以眼角之间的宽度即可。为了增加特征点数量,减少遗漏掉的信息量,68个特征点也首尾相减(转换为位移),一并算入特征当中。对第二步得到的6个人脸纬度信息、2个眼睛开合度信息,和68个特征点位移信息(每个特征点换为x、y位移两个feature),一幅图144个feature,放进LSTM神经网络中进行训练,并预测。
    对图片进行人脸特征点位置检测人脸特征点检测用到了dlib,dlib有两个关键函数:dlib.get_frontal_face_detector()和dlib.shape_predictor(predictor_path)。前者是内置的人脸检测算法,使用HOG pyramid,检测人脸区域的界限(bounds)。后者是用来检测一个区域内的特征点,并输出这些特征点的坐标,它需要一个预先训练好的模型(通过文件路径的方法传入),才能正常工作。

    使用预训练好的模型shape_predictor_68_face_landmarks.dat,可以得到68个特征点位置的坐标,连起来后,可以有如图所示的效果(红色是HOG pyramid检测的结果,蓝色是shape_predictor的结果,仅把同一个器官的特征点连线)。

    三、对特征点进行预处理,得到人脸6维信息、眼睛开合度疲劳驾驶打盹时,人脸会朝下垂,有时会轻微晃动,眼睛会微眯。这和人清醒时目光向前或略微向上,头部稳定转动很不一样。这是我们对疲劳驾驶直观的理解。这些信息放入LSTM网络里训练,让机器自动辨别这些信息,有可能能达到很好的效果。因此,从图片中采集这些信息很重要。
    先讨论人脸6维信息的获得。如前文所述,单目摄像机不含有深度信息,单目的图像信息是无法估算人脸朝向的(因为相当于3维坐标投影到2维平面上,无法还原)。要把2维信息近似还原成3维信息,需要一些额外的信息(或先验知识),如人体测量学中的人脸五官平均距离 (Wikipedia, 2018)。
    这里参考了一篇论文 (Lemaignan S. G., 2016),和他的代码实现 (Lemaignan, 2018)。代码结合OpenCV和Wikipedia给出的人脸五官距离平均值,来对人脸进行建模。我基于作者的代码进行了改造,使其可以批量预处理数据集中的视频截图,并以数组的方式输出人脸6维信息数据。具体的改造和代码运行方法请看我提交的源码。
    使用本算法批量处理数据集中的所有图片。处理完成之后,便额外得到了6维特征,效果如下:

    接下来,计算眼睛开合度信息。68特征点数据分布如图所示 (Rosebrock, 2017):

    右眼开合度可以通过以下公式得到(左眼同理):

    头部6维信息、加眼睛开合度两维信息,共8维信息。如果有可能,还应该采集瞳孔朝向、瞳孔收缩率等信息,但我并没有能成功。如前文所述,一副图片只抽8个特征,信息丢失可能比较多,因此,我把68个坐标点进行一下处理,也作为特征加进去。考虑到坐标本身意义并不大,坐标位移意义反而大一些,我把这些坐标点首尾相减,换算成了位移。一个位移有x、y两个分量,所以这又是136个特征。这样,预处理就完成了。把一张图抽取为144个和脸有关的feature,可以屏蔽掉许多图片细节,如光照、肤色、头的位置(和身高有关)、背景里窗帘的飘动……(尽管可能丢掉有用的信息)。更加重要的是,一张图片变为144个数字,大大简化了输入数据,每一帧输入数据变简单,就让处理帧和帧之间关系(时序信息)变得可能(计算量不至于过大)。
    五、训练LSTM网络模型并进行分类我大学期间并没怎么接触过机器学习,所以这一步更多是依样画瓢,理解不深入。我进行了一些调查后,发现了LSTM网络,可以用来处理时序信息。我尝试了Tensorflow,但感觉还是比较难上手,后来切换到了Keras,用了Keras封装的更加高层、易懂的API。
    Keras的LSTM层输入要求是三维的数据:(样本编号,时间帧编号(timestep),特征向量),预处理完的数据正好是这样三维的,大多数的shape为:(?, 64, 144)。
    我基本就是参考Keras文档中的示例代码,搭建了一个LSTM网络 (Keras, 2018)。在LSTM层后,添加了一层Dense层,模型就搭建完成了。
    训练时,我跑了500个epoch,最终结果为:测试集上78.12%的正确率。而且因为把图片都抽成特征了,所以训练的速度非常快。效果还是比较可喜的。
    六、不足之处和提升空间的讨论LSTM的使用可能不足
    我对机器学习方面的知识所知甚少。特征提取完之后,我在模型搭建和训练这一步做得很有可能不好。如果有机器学习方面才华横溢的人能指点一下,结果很可能能有所提升。也可以试着把LSTM换成别的,如SVM、简单RNN等(疲劳驾驶检测其实可能不需要Long-term memory)。
    单目摄像机获得信息少,人脸信息估计较差
    因为人脸信息估计用到了统计学数据,但这个数据不是很精确,所以最终得到的角度估计效果并不是很好(一些帧存在跳跃现象)。换成双目摄像机,或者RGB-D摄像机,相信特征点提取的效果会好很多。如果疲劳驾驶检测要被广泛投入生产应用,那么升级硬件设备是可行的。
    基于人脸检测的图像处理健壮性略差
    用HOG pyramid方法,一些帧中检测不出人脸(可能因为光照、帽子等原因),虽然这些帧不多,但是它们对整体效果可能有比较大的影响。这些帧,我目前的处理方法是跳过(可能导致时序上不连续)。也可以尝试使用插值的方法来弥补缺失的帧。
    特征抽取仍然不足
    科大讯飞做的系统,可以抽取图片中眼球方向、瞳孔收缩率作为特征。然而本文并没能够抽取出这些特征,因此可能遗漏掉关键的信息。
    七、总结本文尝试了一种基于特征和参数估计的方法,最后一步分类时,仍然用到了深度学习的方法。受限于个人技术能力,许多可能可以进一步提升准确率的工作还没有做,本文分析了这些可能的改进策略。总体而言,实验结果还是不错的,准确率较高,模型训练快速。这足以说明,先提取特征点再使用机器学习的方法,是一条值得探索的路。
    4 评论 40 下载 2019-05-22 10:45:40 下载需要15点积分
  • 图的操作和应用之景区信息管理系统

    一、功能要求1.1 读文件创建图
    输入:从Vex.txt文件中读取景点信息,从Edge.txt文件中读取道路信息
    处理:根据读取的景区信息创建景区景点图

    1.2 查询景点
    输入:想要查询的景点的编号
    处理:根据输入的景点编号,查询该景点及相邻景点的信息
    输出:

    景点名字景点介绍相邻景区的名字到达相邻景区的路径长度

    1.3 旅游景点导航
    输入:起始景点的编号
    处理:使用深度优先搜索(DFS)算法,查询以该景点为起点,无回路游览整个景区的路线
    输出:所有符合要求的导航路线

    1.4 搜索最短路径
    输入:

    起始景点的编号终点的编号
    处理:使用迪杰斯特拉(Dijkstra)算法,求得从起始景点到终点之间的最短路径,计算路径总长度
    输出:

    最短路线路径总长度

    1.5 铺设电路规划
    处理:根据景区景点图使用普里姆(Prim)算法构造最小生成树,设计出一套铺设线路最短,但能满足每个景点都能通电的方案
    输出:

    需要铺设电路的道路-每条道路铺设电路的长度铺设电路的总长度

    1.6 修改图保存文件插入、删除、修改顶点、边的信息,注意顶点和边的关系,之后保存文件,重新读取文件建立图的存储结构并显示。
    重点注意顶点和边的关系,考虑边是否重复?顶点是否存在?……
    二、数据结构介绍#define MAX_SIZE 1000//最大可存顶点数#define INFINITY 99999//无穷大struct Vertex//顶点 { int tag;//标记此顶点是否存在 string name,info;};struct ArcNode { int n; ArcNode *next;};struct VNode//邻接表 { Vertex vex; ArcNode *next;}AdjList[MAX_SIZE];struct Graph//图 { int arc[MAX_SIZE][MAX_SIZE];//每个顶点与其余各个顶点之间边长 int vexnum;//目前顶点总数 int edgnum;//目前此图边总数 int maxvexno; //目前此图顶点最大编号}G;int created=0;//表示未创建图int main()//主函数{ int tag,m,n; while(1) { tag=0; Menu(); cin>>n; switch(n) { case 1:CreatMap();break; case 2:{cout<<"请输入景区编号:"<<endl;cin>>n;SearchVex(n);}break; case 3:{cout<<"请输入景区编号:"<<endl;cin>>n;Navigation_DFS(n);}break; case 4:{cout<<"请输入起止景区编号:"<<endl;cin>>m>>n;ShortestPath_DIJ(m,n);}break; case 5:WirePath_Prim();break; case 6:Edit();break; case 7:tag=1;break; default:cout<<"更多功能正在开发,敬请期待……"<<endl; } if(tag) break; } return 0;}void Menu()//主菜单 { printf("---------------景区管理系统功能菜单---------------\n"); printf("1-----创建图\n"); printf("2-----查询景点信息\n"); printf("3-----旅游景点导航\n"); printf("4-----搜索最短路径\n"); printf("5-----铺设电路规划\n"); printf("6-----修改图\n"); printf("7-----退出主菜单\n"); printf("请输入功能序号执行功能:\n");}
    三、功能实现3.1 数据格式
    Vex.txt中第一行景点总数,之后每一行一个景点信息,包括景点编号、名称、介绍Edge.txt中每一行一条道路信息。包括景点编号、景点编号、道路距离
    3.2 读文件创图将文件中的数据读入内存,建立图的邻接表并输出图的邻接表。
    3.2.1 实现代码void CreatMap()//导入文件数据创建图,并输出邻接表 { int m,t,i,j; //读取Vex.txt文件的景点信息 fstream f1("./Vex.txt",ios::in); f1>>G.vexnum; t=0;//记录已读取景点信息个数 for(i=0;t<G.vexnum;i++) { f1>>m; while(i!=m) { AdjList[i].vex.tag=0;//编号为i的景点不存在,标记为0 i++; } AdjList[m].vex.tag=1; //景点存在,标记为1 t++; f1>>AdjList[m].vex.name>>AdjList[m].vex.info;//从vex.txt文件中读取景点信息 } G.maxvexno=m;//记录景点的最大编号 f1.close(); //初始化各路径距离 for(i=0;i<=G.maxvexno;i++) if(AdjList[i].vex.tag) for(j=0;j<=G.maxvexno;j++) if(AdjList[j].vex.tag) G.arc[i][j]=INFINITY;//初始化各景点间距离为INFINITY //读取Edge.txt的路径信息 fstream f2("./Edge.txt",ios::in); G.edgnum=0; while(f2>>i>>j) { f2>>G.arc[i][j]; G.arc[j][i]=G.arc[i][j];//从Edge.txt文件中读取景点间距离,若文件中未出现两景点间距离则保持初始的INFINITY G.edgnum++; } f2.close(); created=1;//表示已经创建图 //创建邻接表 CreatAdjList(); //展示邻接表 cout<<"邻接表如下:"<<endl;//格式为V1->V2->V3 for(i=0;i<=G.maxvexno;i++) if(AdjList[i].vex.tag) { cout<<'V'<<i; ArcNode *an=AdjList[i].next; while(an) { cout<<"->V"<<an->n; an=an->next; } cout<<endl; }}void CreatAdjList()//建立邻接表 { for(int i=0;i<=G.maxvexno;i++) if(AdjList[i].vex.tag) { ArcNode *a; AdjList[i].next=NULL; for(int j=G.maxvexno;j>=0;j--) if(AdjList[j].vex.tag) if(G.arc[i][j]<INFINITY) { a=new ArcNode; a->n=j; a->next=AdjList[i].next; AdjList[i].next=a; } }}
    3.2.2 数据格式


    编号
    名字
    介绍




    0
    A区
    风景优美,气候宜人。


    1
    B区
    风景优美,气候宜人。


    2
    C区
    风景优美,气候宜人。


    3
    D区
    风景优美,气候宜人。


    4
    E区
    风景优美,气候宜人。


    5
    F区
    风景优美,气候宜人。


    6
    G区
    风景优美,气候宜人。






    景点1
    景点2
    距离(m)




    A
    C
    700


    A
    E
    1000


    A
    F
    600


    B
    C
    1000


    B
    G
    1000


    C
    D
    400


    D
    E
    300


    D
    G
    400


    E
    F
    600


    F
    G
    500



    3.2.3 截图


    3.3 查询景点
    输入:想要查询的景点的编号
    处理:根据输入的景点编号,查询该景点及相邻景点的信息

    输出:

    景点名字景点介绍相邻景区的名字到达相邻景区的路径长度
    算法:根据输入编号直接用数组找到景点信息输出,再用邻接表找到与其相连的景点并输出信息

    3.3.1 实现代码void SearchVex(int n)//查找编号为n的景点 { if(created)//图已被创建 { if(n<0||n>G.maxvexno||AdjList[n].vex.tag==0)//编号n不在文件读入的编号范围内或其标记为0 cout<<"该景点不存在!"<<endl; else {//输出景点编号、名称和景点信息,以及相邻的各个景点编号、名称和相距距离 cout<<n<" "<<AdjList[n].vex.name<<" "<<AdjList[n].vex.info<<endl; cout<<"相邻景点:"<<endl; for(int i=0;i<=G.maxvexno;i++) if(AdjList[i].vex.tag) if(G.arc[i][n]<INFINITY) cout<<i<<" "<<AdjList[i].vex.name<<" "<<G.arc[i][n]<<endl; } } else//图未被创建 cout<<"尚未读取文件创建图!"<<endl;}
    3.3.2 截图
    3.4 修改图保存文件插入、删除、修改顶点、边的信息,注意顶点和边的关系,之后保存文件,重新读取文件建立图的存储结构并显示。
    核心操作:首先要保证添加、删除后仍为连通图(因此添加景点也要添加一条边,删除顶点也要删除相连的边,代码中用IsConnected函数来判断是否连通),否则操作不能执行。其次在操作执行后都要将数据重新读入文件。最后要再一次读取文件创建图。
    3.4.1 实现代码void Edit()//修改操作菜单{ int m; if(created) { while(1) { int tag=0; cout<<"-----编辑操作菜单-----"<<endl; cout<<"-----<1>添加-----"<<endl; cout<<"-----<2>删除-----"<<endl; cout<<"-----<3>修改-----"<<endl; cout<<"-----<4>退出本菜单-----"; cout<<"输入编号执行相应操作:"<<endl; cin>>m; switch(m) { case 1:Add();break; case 2:Delete();break; case 3:Revise();break; case 4:tag=1;break; default:cout<<"更多功能正在开发中,敬请期待……" <<endl; } if(tag) break; } } else cout<<"尚未读取文件创建图!"<<endl;}int count;//记录已访问顶点数 int IsConnected()//判断是否为连通图{ count=0; int *Visited=new int[G.maxvexno+1]; //标记是否已访问过 for(int i=0;i<=G.maxvexno;i++) if(AdjList[i].vex.tag) Visited[i]=0;//初始化 for(int i=0;i<=G.maxvexno;i++) if(AdjList[i].vex.tag) { Connect_DFS(i,Visited); break; } if(count==G.vexnum) return 1;//该图连通,返回1 else return 0; //该图不连通,返回0}void Connect_DFS(int i,int *Visited)//DFS搜索{ ArcNode *an=AdjList[i].next; Visited[i]=1;//标记已访问过 count++;//并入已访问过的点集 cout<<count<<endl; while(an)//搜索与该顶点相连的每个顶点 { while(Visited[an->n]||AdjList[an->n].vex.tag==0)//已访问过就找下一个顶点 { an=an->next; if(an==NULL)break; } if(an) { Connect_DFS(an->n,Visited);//对此顶点进行DFS搜索 an=an->next; } }}void Add()//添加操作菜单 { int n,tag; while(1) { tag=0; cout<<"Vex.txt内容读取:"<<endl; ShowVexTxt(); cout<<"Edge.txt内容读取:"<<endl; ShowEdgeTxt(); cout<<"--------添加选项------"<<endl; cout<<"-----<1>景点-----" <<endl; cout<<"-----<2>路径-----"<<endl; cout<<"-----<3>退出当前菜单-----"<<endl; cout<<"输入功能序号执行相应功能:"<<endl; cin>>n; switch(n) { case 1:AddVex();break; case 2:AddEdge();break; case 3:tag=1;break; default:cout<<"更多功能正在开发,敬请期待……"<<endl; } if(tag) break; }}void AddVex()//添加景点 { int no,start,end,dis,maxno; string name,info; if(G.vexnum<MAX_SIZE) { cout<<"请输入添加的景点及路径:(第一行:景点编号 名称 信息 第二行:景点编号 景点编号 距离)"<<endl; cin>>no>>name>>info; cin>>start>>end>>dis; if(no<0) cout<<"景点编号不合法!添加失败!"<<endl; else { if(no>G.maxvexno||AdjList[no].vex.tag==0) {//初始化该景点相关信息 AdjList[no].vex.tag=1; AdjList[no].vex.name=name; AdjList[no].vex.info=info; G.vexnum++; maxno=G.maxvexno; if(no>G.maxvexno)//更改最大编号,并将不存在的顶点标记 { for(int i=G.maxvexno+1;i<no;i++) AdjList[i].vex.tag=0; G.maxvexno=no; } for(int i=0;i<=G.maxvexno;i++)//初始化no与其他顶点的距离 if(AdjList[i].vex.tag) { G.arc[i][no]=INFINITY; G.arc[no][i]=INFINITY; } //添加道路 if(start<0||start>G.maxvexno||AdjList[start].vex.tag==0||end<0||end>G.maxvexno||AdjList[end].vex.tag==0) cout<<"景点不存在!添加失败!"<<endl; else if(dis<=0||dis>=INFINITY) cout<<"该路径距离超限!添加失败!"<<endl; else if(G.arc[start][end]<INFINITY) cout<<"该路径已记录!添加失败!"<<endl; else { G.arc[start][end]=dis; G.arc[end][start]=dis; G.edgnum++; CreatAdjList();//重建邻接表 if(IsConnected())//添加后仍是连通图 { fstream f3("./Vex.txt",ios::out); fstream f4("./Edge.txt",ios::out); //读入Vex文件 f3<<G.vexnum<<endl; for(int i=0;i<=G.maxvexno;i++) if(AdjList[i].vex.tag) f3<<i<<' '<<AdjList[i].vex.name<<' '<<AdjList[i].vex.info<<endl; f3.close(); //读入Edge文件 for(int i=0;i<=G.maxvexno;i++) if(AdjList[i].vex.tag) for(int j=i;j<=G.maxvexno;j++) if(AdjList[j].vex.tag) if(G.arc[i][j]<INFINITY) f4<<i<<' '<<j<<' '<<G.arc[i][j]<<endl;; f4.close(); cout<<"添加景点成功!"<<endl; } else//否则添加失败 {//更改为添加前的值 AdjList[no].vex.tag=0; G.vexnum--; G.maxvexno=maxno; G.arc[start][end]=INFINITY; G.arc[end][start]=INFINITY; G.edgnum--; cout<<"添加后为非连通图!添加失败!"<<endl; } //重新创建图 CreatMap(); } } else cout<<"该景点已存在!添加失败!"<<endl; } } else cout<<"景点存储数量已达上限,无法再添加!"<<endl;}void AddEdge()//添加道路{ int start,end,dis; //添加道路 cout<<"请输入添加的路径:(景点编号 景点编号 距离)"<<endl; cin>>start>>end>>dis; if(start<0||start>G.maxvexno||AdjList[start].vex.tag==0||end<0||end>G.maxvexno||AdjList[end].vex.tag==0) cout<<"景点不存在!添加失败!"<<endl; else if(dis<=0||dis>=INFINITY) cout<<"该路径距离超限!添加失败!"<<endl; else if(G.arc[start][end]<INFINITY) cout<<"该路径已记录!添加失败!"<<endl; else { G.arc[start][end]=dis; G.arc[end][start]=dis; G.edgnum++; CreatAdjList();//重建邻接表 if(IsConnected())//添加后仍是连通图 { fstream f5("./Edge.txt",ios::out); //读入Edge文件 for(int i=0;i<=G.maxvexno;i++) if(AdjList[i].vex.tag) for(int j=i;j<=G.maxvexno;j++) if(AdjList[j].vex.tag) if(G.arc[i][j]<INFINITY) f5<<i<<' '<<j<<' '<<G.arc[i][j]<<endl; f5.close(); cout<<"添加路径成功!"<<endl; } Else//添加后不是连通图 {//恢复原值 G.arc[start][end]=INFINITY; G.arc[end][start]=INFINITY; G.edgnum--; cout<<"添加后为非连通图!添加失败!"<<endl; } CreatMap();//重新创建图 }}
    3.4.2 截图





    void Revise()//修改操作菜单 { int n,tag; while(1) { tag=0; cout<<"Vex.txt内容读取:"<<endl; ShowVexTxt(); cout<<"Edge.txt内容读取:"<<endl; ShowEdgeTxt(); cout<<"--------修改选项------"<<endl; cout<<"-----<1>景点-----" <<endl; cout<<"-----<2>路径-----"<<endl; cout<<"-----<3>退出当前菜单-----"<<endl; cout<<"请输入功能序号执行相应功能:"<<endl; cin>>n; switch(n) { case 1:ReviseVex();break; case 2:ReviseEdge();break; case 3:tag=1;break; default:cout<<"更多功能正在开发,敬请期待……"<<endl; } if(tag) break; } }void ReviseEdge()//修改道路距离{ //修改路径信息 int m,n,start,end,dis; cout<<"请输入要修改路径距离的路径个数:(不得超过"<<G.edgnum<<"个)"<<endl; cin>>n; while(n<0||n>G.edgnum) { cout<<"已超过已存在路径个数!请重新输入:"<<endl; cin>>n; } m=n; cout<<"请逐行输入路径新信息:(格式:景点编号 景点编号 距离)"<<endl; while(n) { cin>>start>>end>>dis; if(start<0||start>G.maxvexno||AdjList[start].vex.tag==0||end<0||end>G.maxvexno||AdjList[end].vex.tag==0) cout<<"景点不存在!请重新输入修改信息:"<<endl; else if(dis<=0||dis>=INFINITY) cout<<"该路径距离超限!请重新输入修改信息:"<<endl; else if(G.arc[start][end]==INFINITY) cout<<"该路径不存在!请重新输入修改信息:"<<endl; else { G.arc[start][end]=dis; G.arc[end][start]=dis; n--; } } fstream f7("./Edge.txt",ios::out); //读入文件 for(int i=0;i<=G.maxvexno;i++) if(AdjList[i].vex.tag) for(int j=i;j<=G.maxvexno;j++) if(AdjList[j].vex.tag) if(G.arc[i][j]<INFINITY) f7<<i<<' '<<j<<' '<<G.arc[i][j]<<endl; f7.close(); cout<<m<<"条路径信息已成功修改!"<<endl; CreatMap();//重新创建图 }void ReviseVex()//修改景点信息{ int m,n,no; string name,info; //修改景点信息 cout<<"请输入要修改的景点信息的景点个数:(不得超过"<<G.vexnum<<"个)"<<endl; cin>>n; while(n<0||n>G.vexnum) { cout<<"已超过目前已存在景点个数!请重新输入:"<<endl; cin>>n; } m=n; cout<<"请逐行输入景点新信息:(格式:编号 景点名 介绍)"<<endl; while(n) { cin>>no>>name>>info; if(no>=0&&no<G.maxvexno&&AdjList[no].vex.tag) { AdjList[no].vex.name=name; AdjList[no].vex.info=info; n--; } else cout<<"该景点不存在!请重输修改信息:"<<endl; } //读入文件 fstream f6("./Vex.txt",ios::out); f6<<G.vexnum<<endl; for(int i=0;i<=G.maxvexno;i++) if(AdjList[i].vex.tag) f6<<i<<' '<<AdjList[i].vex.name<<' '<<AdjList[i].vex.info<<endl; f6.close(); cout<<m<<"条景点信息已成功修改!"<<endl; CreatMap();//重新创建图 }






    void Delete()//删除操作菜单{ int n,tag; while(1) { tag=0; cout<<"Vex.txt内容读取:"<<endl; ShowVexTxt(); cout<<"Edge.txt内容读取:"<<endl; ShowEdgeTxt(); cout<<"--------删除选项------"<<endl; cout<<"-----<1>景点-----" <<endl; cout<<"-----<2>路径-----"<<endl; cout<<"-----<3>退出当前菜单-----"<<endl; cout<<"输入功能序号执行相应功能:"<<endl; cin>>n; switch(n) { case 1:DeleteVex();break; case 2:DeleteEdge();break; case 3:tag=1;break; default:cout<<"更多功能正在开发,敬请期待……"<<endl; } if(tag) break; }}void DeleteVex()//删除景点{ int no,maxno; cout<<"请输入要删除的编号:"<<endl; cin>>no; if(no<0||no>G.maxvexno||AdjList[no].vex.tag==0) cout<<"景点不存在!删除失败!"<<endl; else { G.vexnum--; AdjList[no].vex.tag=0;//修改标记 maxno=G.maxvexno; if(no==G.maxvexno)//更新最大编号 for(int i=G.maxvexno-1;i>=0;i--) if(AdjList[i].vex.tag) { G.maxvexno=i; break; } CreatAdjList();//重建邻接表 if(IsConnected()) {//删除后连通 fstream f8("./Vex.txt",ios::out); //读入Vex文件 f8<<G.vexnum<<endl; for(int i=0;i<=G.maxvexno;i++) if(AdjList[i].vex.tag) f8<<i<<' '<<AdjList[i].vex.name<<' '<<AdjList[i].vex.info<<endl; f8.close(); fstream f9("./Edge.txt",ios::out); //更新删除顶点后的路径并读入Edge文件 G.edgnum=0; for(int i=0;i<=G.maxvexno;i++) if(AdjList[i].vex.tag) for(int j=i;j<=G.maxvexno;j++) if(AdjList[j].vex.tag) if(G.arc[i][j]<INFINITY) { f9<<i<<' '<<j<<' '<<G.arc[i][j]<<endl; G.edgnum++; } f9.close(); cout<<"成功删除景点!"<<endl; } else {//不连通则恢复原值 G.vexnum++; AdjList[no].vex.tag=1;//修改标记 G.maxvexno=maxno; cout<<"删除后为非连通图!删除失败!"<<endl; } CreatMap();//重新创建图 }} void DeleteEdge()//删除道路{ int n,m,dis,start,end; //删除路径信息 cout<<"请输入要删除的路径个数:(不得超过"<<G.edgnum-G.vexnum+1<<"个)"<<endl; cin>>n; while(n<0||n>G.edgnum-G.vexnum+1) { cout<<"已超过可删除路径数限制!请重新输入:"<<endl; cin>>n; } m=n; cout<<"请逐行输入路径连接的两景点:(格式:景点编号 景点编号)"<<endl; while(n) { cin>>start>>end; if(start<0||start>G.maxvexno||AdjList[start].vex.tag==0||end<0||end>G.maxvexno||AdjList[end].vex.tag==0) cout<<"景点不存在!请重新输入删除信息:"<<endl; else if(G.arc[start][end]==INFINITY) cout<<"该路径不存在!请重新输入删除信息:"<<endl; else { dis=G.arc[start][end]; G.arc[start][end]=INFINITY; G.arc[end][start]=INFINITY; G.edgnum--; n--; CreatAdjList();//重建邻接表 if(IsConnected()) {//删除后仍连通 fstream f10("./Edge.txt",ios::out); //读入文件 for(int i=0;i<=G.maxvexno;i++) if(AdjList[i].vex.tag) for(int j=i;j<=G.maxvexno;j++) if(AdjList[j].vex.tag) if(G.arc[i][j]<INFINITY) f10<<i<<' '<<j<<' '<<G.arc[i][j]<<endl; f10.close(); cout<<"成功删除路径!"<<endl; } else {//不连通则恢复原值 G.arc[start][end]=dis; G.arc[end][start]=dis; G.edgnum++; cout<<"删除后为非连通图!删除失败!"<<endl; } } } cout<<m<<"条路径删除完毕!"<<endl; CreatMap();//重新创建图 }






    3.5 旅游景点导航
    输入:起始景点的编号
    处理:使用深度优先搜索(DFS)算法,查询以该景点为起点,无回路游览整个景区的路线
    输出:所有符合要求的导航路线
    算法:对DFS进行改良,对一个景点连接的所有景点都进行搜索,每一个都可以搜索出一条新路(用两个数组,一个数组用来标记本条路上访问过的景点,另一个数组标记搜索连接的景点中已搜索过的景点),以此递归,最终如果本条路上的景点数等于景点总数,说明该路无回路

    3.5.1 代码实现void Navigation_DFS(int n)//DFS算法从编号为n的景点开始无回路遍历全图 { if(created)//图已被创建 { if(n<0||n>G.maxvexno||AdjList[n].vex.tag==0)//编号n不在文件读入的编号范围内或顶点标记为0 cout<<"该景点不存在!"<<endl; else { int count=1;//count记录本条路径已搜索过的顶点 int *BVisited=new int[G.maxvexno+1];//横向标记 int *DVisited=new int[G.maxvexno+1];//纵向标记 int *no=new int[G.vexnum];//记录路径上的顶点编号 for(int i=0;i<=G.maxvexno;i++) if(AdjList[i].vex.tag) { DVisited[i]=0;//复制前面纵向搜索的标记 BVisited[i]=0;//横向均未搜索过 } no[0]=n;//记录起点 DVisited[n]=1;//标记纵向已访问过 ArcNode *an=AdjList[n].next; while(an)//横向搜索与该顶点相连的每个顶点 { while(BVisited[an->n])//横向或纵向已访问过就找下一个顶点 { an=an->next; if(an=NULL)break; } if(an) { DFS(an->n,count,DVisited,no);//对此顶点进行DFS搜索 BVisited[an->n]=1;//标记此顶点横向已访问过 an=an->next; } } } } else//图未被创建 cout<<"尚未读取文件创建图!"<<endl;}void DFS(int n,int count,int *a,int *no)//DFS搜索路径 { int *DVisited=new int[G.maxvexno+1];//纵向标记 int *BVisited=new int[G.maxvexno+1];//横向标记 for(int i=0;i<=G.maxvexno;i++) if(AdjList[i].vex.tag) { DVisited[i]=a[i];//复制前面纵向搜索的标记 BVisited[i]=0;//横向均未搜索过 } no[count++]=n; DVisited[n]=1;//纵向标记已访问过 ArcNode *an=AdjList[n].next; while(an)//横向搜索与该顶点相连的每个顶点 { while(BVisited[an->n]||DVisited[an->n])//横向或纵向已访问过就找下一个顶点 { an=an->next; if(an==NULL)break; } if(an) { DFS(an->n,count,DVisited,no);//对此顶点进行DFS搜索 BVisited[an->n]=1;//标记此顶点横向已访问过 an=an->next; } } if(count==G.vexnum)//如果此路径上顶点数与总顶点数相同,说明该路径无回路 { for(int i=0;i<count-1;i++)//输出路径 cout<<AdjList[no[i]].vex.name<<"-->"; cout<<AdjList[count-1].vex.name<<endl; }}
    3.5.2 截图


    DFS核心代码流程图

    3.6 搜索最短路径
    输入:

    起始景点的编号终点的编号
    处理:使用迪杰斯特拉(Dijkstra)算法,求得从起始景点到终点之间的最短路径,计算路径总长度
    输出:

    最短路线路径总长度
    算法:先用Dijkstra算法,然后根据两个景点编号输出其最短路径。优点是可以找到任意两点间最短路径,缺点是遍历的节点太多,效率很低

    3.6.1 代码实现void ShortestPath_DIJ(int m,int n)//Dijkstra算法求编号m景区到编号n景区的最短路线 { if(created) { if(m<0||m>G.maxvexno||AdjList[m].vex.tag==0||n<0||n>G.maxvexno||AdjList[n].vex.tag==0) cout<<"景点不存在"<<endl; else { int *Pre=new int[G.maxvexno+1];//记录当前顶点的前一顶点 int *Dis=new int[G.maxvexno+1];//起点到各个顶点的当前最短距离 int *final=new int[G.maxvexno+1];// 记录是否已找到起点到各个顶点的最短路径 for(int i=0;i<=G.maxvexno;i++)//初始化 if(AdjList[i].vex.tag) { final[i]=0;//表示起点到各个顶点的最短距离均未找到 Dis[i]=G.arc[m][i];//初始化起点到各个顶点的最短距离,与起点相连的就是连线的距离,否则就是INFINITY if(Dis[i]<INFINITY) Pre[i]=m;//最短距离小于INFINITY,表明与起点相连,则其前一顶点为起点 else Pre[i]=-1;//否则置为-1,表示无前一顶点 } Dis[m]=0;//起点到自身距离为0 final[m]=1;//起点到起点已找到最短路径 for(int i=0;i<=G.maxvexno;i++) if(AdjList[i].vex.tag) { int min=INFINITY;//记录离起点最近的距离 int v=-1;//记录离起点最近的点 for(int j=1;j<=G.maxvexno;j++)//从未找到最短路径的顶点中找到离起点最近的顶点 if(AdjList[j].vex.tag) if(!final[j]&&Dis[j]<min) { min=Dis[j]; v=j; } final[v]=1;//起点到该点已找到最短距离 for(int j=0;j<=G.maxvexno;j++) if(AdjList[j].vex.tag) if(!final[j]&&(min+G.arc[v][j]<Dis[j]))//更新起点到各点的最短距离 { Dis[j]=min+G.arc[v][j]; Pre[j]=v;//记录前一顶点 } } cout<<"从"<<AdjList[m].vex.name<<"至"<<AdjList[n].vex.name; if(Dis[n]<INFINITY)//倒序输出路径 { cout<<"最短路径总长度为"<<Dis[n]<<" 最短路径(倒序)如下:"<<endl; cout<<AdjList[n].vex.name; int v=Pre[n]; while(v!=m) { cout<<"<--"<<AdjList[v].vex.name; v=Pre[v]; } cout<<"<--"<<AdjList[m].vex.name<<endl; } else cout<<"不通!"<<endl; } } else//图未被创建 cout<<"尚未读取文件创建图!"<<endl;}
    3.6.2 截图
    核心代码流程图

    3.7 铺设电路规划
    处理:根据景区景点图使用普里姆(Prim)算法构造最小生成树,设计出一套铺设线路最短,但能满足每个景点都能通电的方案
    输出:

    需要铺设电路的道路每条道路铺设电路的长度铺设电路的总长度
    算法:Prim算法,适用于边数多的图

    3.7.1 代码实现void WirePath_Prim()//Prim算法求铺设最短电路 { struct { int vexno; int lowcost; }closedge[MAX_SIZE];//记录当前已经确定的点集到某顶点i的最短距离及对应顶点编号 int sum=0;//总长度 int t;//记录一个顶点编号,以此顶点为起点 for(int i=0;i<=G.maxvexno;i++)//找t if(AdjList[i].vex.tag) { t=i; break; } for(int i=0;i<=G.maxvexno;i++)//初始化已确定点集仅含t if(AdjList[i].vex.tag) { closedge[i].vexno=t; closedge[i].lowcost=G.arc[t][i]; } closedge[t].lowcost=0;//表示该顶点属于已确定点集 for(int i=1;i<=G.vexnum;i++)//将其余G.vexnum-1个顶点并入已确定点集中 { int vex2=-1,vex1=-1,min=INFINITY; for(int j=0;j<=G.maxvexno;j++)//找与已确定点集距离最近的顶点 if(AdjList[j].vex.tag) if(closedge[j].lowcost>0&&closedge[j].lowcost<INFINITY) if(closedge[j].lowcost<min) { min=closedge[j].lowcost; vex2=j; vex1=closedge[j].vexno;//与该顶点相连的已确定点集中的某一顶点 } if(vex1==-1&&vex2==-1)//搜索结束 break; cout<<AdjList[vex1].vex.name<<"-->"<<AdjList[vex2].vex.name<<" "<<min<<endl;//输出最短距离及连接的两点 closedge[vex2].lowcost=0;//将该顶点并入已确定点集 sum+=min;//总长度更新 for(int j=0;j<=G.maxvexno;j++)//更新已确定点集到各顶点的最短距离 if(G.arc[vex2][j]<closedge[j].lowcost) { closedge[j].vexno=vex2; closedge[j].lowcost=G.arc[vex2][j]; } } cout<<"电路总长:"<<sum<<endl;//输出电路总长 }
    3.7.2 截图
    核心代码流程图

    四、总结首先对DFS、迪杰斯特拉、Prim算法都再次深入理解了一遍,而且能更加熟练的运用和修改后适用于新问题,同时也对算法的利弊有所体会。
    再一个就是学会了使用文件的读取和读写流,文件数据修改后应该重新写入文件,以及重新创建相应的图。
    这个过程中,一个很重要的问题还是指针的熟练掌握和运用,对于所创建的数据结构必要时要在数据的末尾指针赋空,这样检索遍历时不会混乱。
    在刚开始程序写完运行的时候很容易出现烫烫烫,就是因为传值没有传过来,数据没有初始化等原因。
    另外,通过设计这个程序,让我对于程序的整体性、容错性以及尽可能让软件输入简洁明了有了更深的认识,尽可能让用户输入正确的数据,这样才能保证程序不会因为用户输错数据类型而崩溃;其次还有用户输入的数据必须有效,这就需要代码去识别,如果无效必须进行处理,否则也会引起崩溃。
    主要考察的修改操作这一块,要求很强的逻辑性,必须处理好修改成功与否与文件是否重新读写的关系。因为整个程序是在连通图的大前提下,所以无论哪一步操作都要注意操作后图是否连通,如果连通方可修改,否则不能执行操作。修改后还要对应重新读写文件创建新图。
    总之,在写程序时要全面考虑,不管要考虑需求,还要对程序的容错性最大限度地考虑到,保证程序在用户输错数据的情况下依然能够正常运行。
    1 评论 2 下载 2019-09-20 07:15:04 下载需要7点积分
  • 基于java的作业管理系统

    一、项目背景随着互联网技术的迅猛发展,网络给人们带来了很多便利,比如人们借助于网络进行相互交流、相互通信、共享信息、文件的上传下载等。同时互联网的发展也推动了教育的发展和变革,现在不少高校都有自己的作业提交系统,由于各种原因我们川大还没有统一的使用作业提交系统。为了更好的利用校园网的软硬件资源,实现学生作业的无纸化管理,让学生提交作业、查询作业信息更为方便,让老师审核学生作业更加的快捷,我们决定基于B/S结构开发一个简单又实用的在线提交作业系统。
    二、理论基础2.1 数据库技术PostgreSQL 是一种对象-关系型数据库管理系统(ORDBMS),也是目前功能最强大、特性最丰富和最复杂的自由软件数据库系统.它起源于伯克利(BSD)的数据库研究计划,目前是最重要的开源数据库产品开发项目之一, 有着非常广泛的用户。
    PostgreSQL 是唯一支持事务、子查询、多版本并行控制系统、数据完整性检查等特性的唯一的一种自由软件的数据库管理系统.能在多平台下—-包括Linux、FreeBSD和Windows等—-运行,并且支持多语言的开发。
    我们采用PostgreSQL8.4作为我们的数据库系统。
    2.2 2B/S架构的WEB程序设计技术B/S结构(Browser/Server结构)即浏览器和服务器结构。它是随着Internet技术的发展,对C/S结构的一种变化或者改进的结构。在这种结构下,用户工作界面是通过网页浏览器来实现,极少部分事务逻辑在前端(Browser)实现,但是主要事务逻辑在服务器端(Server)实现,形成所谓三层3-tier结构。这样就大大简化了客户端电脑载荷,减轻了系统维护与升级的成本和工作量,降低了用户的总体成本(TCO)。以目前的技术看,局域网建立B/S结构的网络应用,并通过Internet/Intranet模式下数据库应用,相对易于把握、成本也是较低的。它是一次性到位的开发,能实现不同的人员,从不同的地点,以不同的接入方式(比如LAN, WAN, Internet/Intranet等)访问和操作共同的数据库;它能有效地保护数据平台和管理访问权限,服务器数据库也很安全 。B/S结构最大的优点就是可以在任何地方进行操作而不用安装任何专门的软件。只要有一台能上网的电脑就能使用,客户端零维护。系统的扩展非常容易,只要能上网,再由系统管理员分配一个用户名和密码,就可以使用了。甚至可以在线申请,通过公司内部的安全认证(如CA证书)后,不需要人的参与,系统可以自动分配给用户一个账号进入系统。
    三层客户/服务器(B/S)体系结构

    客户端仅仅运行用户界面,浏览器(Web browser)用于数据的呈现 瘦客户;应用服务器运行业务逻辑和数据处理,应用服务器 + Web server ;数据库服务器提供企业数据的集成和管理。
    三、需求分析3.1 系统用例图
    3.2 系统功能体系图
    3.3 目标完成一套网上提交作业系统,练习体验Web数据库应用开发,最终希望可以把源代码提供给学校使用,能够完成简单的作业管理任务,讲源代码公开,希望有更多的同学参与进来将这个系统修改和完善。
    3.4 用户的特点用户对象是川大老师和同学,基于同学和老师对计算机技术有一定了解,可以很快熟悉系统的使用方法。也正是这个原因,我们将尽可能简单的设计我们的系统,把更多的主动权交给用户,以此来满足用户的需求。管理员对计算机很了解,不过我们希望管理员只做很少一部分,即对部分老师和学生的不规范行为矫正,如老师的作业没有在一定时间内删除,学生毕业后没有注销等。
    3.5 基本功能
    不同用户登陆进入不同的用户界面
    学生、教师的信息修改和密码修改
    学生、教师的注册注销
    学生、教师可以多次上传文件覆盖上一次作业
    学生注册课程
    学生添加小组和加入小组
    组长管理组员
    学生查看作业和下载作业
    学生、小组上传提交作业
    学生查看教师通知
    教师添加注册课程
    教师布置作业
    教师发布关于作业通告
    教师查看选课情况和学生和小组信息
    教师查看和统计提交作业情况(人数、日期等)
    教师下载学生和小组作业

    3.6 对性能的规定要求系统支持PostGreSQL数据库
    3.7 限制条件
    学生不可以进行教师页面
    教师也不可以进入学生页面
    每个学生登录进入之后只能看到自己注册课程的作业,不要恶意注册其他没有选的课程
    每个教师登录只对自己发布的作业进行管理,不可以对别的教师发布的作业进行管理
    不同的用户使用修改密码都只能修改自己的密码,无法修改他人的
    不同的用户使用个人数据功能时,也是只可以看到自己的信息不可以看到他们的信息
    学生上传作业的类型,大小受系统约束,

    3.8 系统难点分析数据库的设计,推广本系统的话就要减少防止数据库的三类异常,同时兼顾效率,要在两者之间取舍。
    四、系统总体软件结构图4.1 MVC架构图
    控制器起到不同层面间的组织作用,用于控制应用程序的流程。它处理事件并作出响应。“事件”包括用户的行为和数据模型上的改变。
    视图层能够实现数据有目的的显示(理论上,这不是必需的)。在视图中一般没有程序上的逻辑。为了实现视图上的刷新功能,视图需要访问它监视的数据模型(Model),因此应该事先在被它监视的数据那里注册。
    “数据模型”(Model)用于封装与应用程序的业务逻辑相关的数据以及对数据的处理方法。“模型”有对数据直接访问的权力,例如对数据库的访问。“模型”不依赖“视图”和“控制器”,也就是说,模型不关心它会被如何显示或是如何被操作。但是模型中数据的变化一般会通过一种刷新机制被公布。为了实现这种机制,那些用于监视此模型的视图必须事先在此模型上注册,从而,视图可以了解在数据模型上发生的改变。
    4.2 系统包图
    Controller包控制系统程序的流程,并对事物作出响应,其中的servlet接受JSP中提交的信息后,调用Module包中的Action类,然后Action再调用DaoImpl中的方法,DaoImpl完成了和数据库的连接,具有访问数据库的权利。这种结构,使得调用结构更加清晰,容易调试错误和以后对程序功能的扩展。JavaBean包定义了系统中的各种自定义数据结构。
    五、详细设计5.1 E-R图
    5.2 关系模式Student(student_id,student_name,student_gender,grade,classes,student_sdept,mail,password);



    Student Table








    属性
    类型
    长度
    约束条件



    student_id
    varchar
    20
    主码



    student_name
    varchar
    20
    不为空



    student_gender
    varchar
    8
    ‘男’或‘女’



    grade
    varchar
    8




    classes
    varchar
    8




    student_sdept
    varchar
    20




    mail
    varchar
    30




    Password
    varchar
    20
    不为空



    Teacher(teacher_id,teacher_name,teacher_gender,mail,domain,password);



    Teacher Table








    属性
    类型
    长度
    约束条件



    teacher_id
    varchar
    20
    主码



    teacher_name
    varchar
    20
    不为空



    teacher_gender
    varchar
    8
    ‘男’或‘女’



    domain
    varchar
    20




    mail
    varchar
    30




    Password
    varchar
    20
    不为空



    Homework(homework_id,homework_filename,message);



    Homework Table








    属性
    类型
    长度
    约束条件



    homework_id
    varchar
    20
    主码



    homework_filename
    varchar
    20
    不为空



    message
    varchar
    250




    score
    float





    Course(course_id,course_name,course_sdept);



    Course Table








    属性
    类型
    长度
    约束条件



    course_id
    varchar
    20
    主码



    course_name
    varchar
    20
    不为空



    course_sdept
    varchar
    20




    Team(team_id,team_name,team_monitorid);



    Team Table








    属性
    类型
    长度
    约束条件



    team_id
    varchar
    20
    主码



    team_name
    varchar
    20
    不为空



    team_monitorid
    varchar
    20




    Student_team(student_id,team_id);(不完全遵守转换规则)



    Student_team Table








    属性
    类型
    长度
    约束条件



    team_id
    varchar
    20
    外码



    student_id
    varchar
    20
    外码



    Team_monitorid
    varchar
    20




    Homework_student(student_id,homework_id);(不完全遵守转换规则)



    Student_team Table








    属性
    类型
    长度
    约束条件



    homework_id
    varchar
    20
    外码



    student_id
    varchar
    20
    外码



    Course_id
    varchar
    20




    submit_date
    Date

    不为空



    Teacher_id
    varchar
    20




    Homework_team(student_id,homework_id);(不完全遵守转换规则)



    Student_team Table








    属性
    类型
    长度
    约束条件



    homework_id
    varchar
    20
    外码



    team_id
    varchar
    20
    外码



    Course_id
    varchar
    20




    submit_date
    Date

    不为空



    Teacher_id
    varchar
    20




    Teacher_course(teacher_id,course_id);



    Student_team Table








    属性
    类型
    长度
    约束条件



    teacher_id
    varchar
    20
    外码



    course_id
    varchar
    20
    外码



    Teacher_course_homeowrk(teacher_id,course_id);



    Student_team Table








    属性
    类型
    长度
    约束条件



    teacher_id
    varchar
    20
    外码



    course_id
    varchar
    20
    外码



    homework_id
    varchar
    20
    外码



    homework_date
    Date

    不为空



    5.3 软件包类图5.3.1 Action包图本包属于Module,Action包接受Controller包中servlet的调用,对其隐藏细节而完成系统的各个功能,其中包括了上传作业(下载作业不作为一个类)、添加删除学生、查找课程和作业等类。

    5.3.2 Bean包图本包属于Module,对Action包和Dao包中的数据结构进行自定义,其中包括了学生信息、教师信息和课程信息等类。

    5.3.3 Controller包图本包属于Controller,对用户事件作出反应,用于处理浏览器中的表单和返回查询结果,通过本包调用Action包完成查询。

    5.3.4 Dao包图接收Action的调用,访问数据库完成一次数据库操作。

    5.4 部分功能算法和代码5.4.1 文件上传的流程图
    效果截图:


    5.4.2 分页技术部分代码:
    String sql = "select course.course_id,course.course_name,course.teacher_id,course.teacher_name from course left outer join student_course on student_course.student_id=? and course.course_id=student_course.course_idand course.teacher_id=student_course.teacher_id where student_course.student_id !=? or student_course.student_id is null order by course.course_id limit 1 offset ?";
    效果图:(为展示效果我们将limit值设为 1,每页显示一项)

    5.4.3 小组删除识别效果图小组组长进行此操作将会删除这个小组,而小组成员操作知识退出小组。


    5.4.4 老师部分功能老师注册课程

    老师端的主界面:包含了主要功能,后期可以扩展

    查看作业提交情况,分别以个人和小组来分类

    查看学生个人作业,并且下载学生作业

    以小组为单位查看作业并下载

    布置课程作业,可以覆盖前次上传

    六、讨论和展望6.1 系统优点这是我们小组成员第一次合作,也是第一次做关于Jsp和数据库的应用系统,系统的基本功能已经实现,并且我们为以后的进一步开发业预留了接口和余地。在保证基本功能的同时我们也尽力为用户提供良好界面交互,也尽可能的接近可以应用的系统,为此我们添加了分页、重复上传和删除时识别权限等功能。
    6.2 系统缺点同样由于第一做此类系统,并且时间有点紧,所以系统还有很大缺点。功能不完善,我们在当初考虑要设计管理员,但是由于时间紧迫我们没有实现这方面的功能。教师和学生端的一些功能也有待进一步补充,教师端的发送群邮件没有完成。
    还有就是系统界面,这是我们最后提交系统给助教老师检查前的最大担心,也是我们最大的遗憾,没有在最后做出一个交互良好的界面。
    我们小组对于自己系统距离可以投入使用的差距很清楚,并且经过前面开发的经验和教训,如果有机会有时间的的话,可以根据上诉缺点一一改正,并且可以做到真正使用。
    6.3 系统设计和开发过程中的收获通过这次课程实践,我们对数据库的设计方法有了清晰的认识,即需求分析、概念设计、逻辑设计,对设计ER图和ER向关系模式的转换,这个过程中我们接受了书上的观点,为了提高代码效率和代码重用率我们允许了一些冗余。
    通过系统开发,我们对SQL语句的应用更加熟练,在进行分页过程中,总是遇到想不到的问题,然后我们将Servlet之间的逻辑关系画出来,一边编写代码,一边解释代码意思,这样总算做出了“健壮”的分页。在学习查询优化之后,我们又试图将一些SQL语句进行优化,不过不能直观的对比两种方式的效果。此外还获得了网页开发和软件工程方面的一些知识和经验,比如CSS。
    这次是我们小组成员的第一次合作,讨论决定这个项目后,我们在网上找资料、找视频,在图书馆看书学习,但效果很不好,写过一些代码,但随着后来任务的增多和小组成员的分工,开发进度越来越慢,后来由决定放弃,原来的开发模式,参考老师提供的项目代码和学习PPT后,我们决定按照MVC的模式从新开始工作。之后开发进度逐渐顺利起来,小组分工慢慢协调起来。整个项目坐下来,也从中体会了很多技术之外的东西,小组之间的交流和协调对于软件开发也是举足轻重。
    最后,要感谢数据库老师对我们不耐其烦的指导,如果没有老师帮助我们不可能顺利开发。还要感谢助教对我们系统的检查以及对我们提出的建议和批评,让我们认识到我们的缺点。我们将尽力推出更好的版本。
    1 评论 35 下载 2019-03-16 20:33:48 下载需要11点积分
  • 基于Keras和tensorflow深度学习Python实现的支持人脸识别和情绪分类的社区APP网站和微信小程序

    1 项目介绍1.1 背景视觉使人类得以感知和理解周边的世界,人的大脑皮层大约有 70%的活动在处理 视觉相关信息。计算机视觉即通过电子化的方式来感知和理解影像,以达到甚至超 越人类视觉智能的效果。
    从 1966 年学科建立(MIT:TheSummerVisionProject)至今,尽管计算机视觉在 感知与认知智能方向仍有大量难以解决、尚待探索的问题,但得益于深度学习算法 的成熟应用(2012 年,采用深度学习架构的 AlexNet 模型,以超越第二名 10 个百 分点的成绩在 ImageNet 竞赛中夺冠),侧重于感知智能的图像分类技术在工业界逐 步实现商用价值,助力金融、安防、互联网、手机、医疗、工业等领域智能升级。

    2016 年下半年开始,人脸识别、视频结构化等计算机视觉相关技术在安防领域 的实战场景中突破工业化红线,敲响了计算机视觉行业市场大规模爆发的前奏。预 计在未来三年内中国计算机视觉行业市场规模将迎来较大增长。

    伴随人脸识别、物体识别等分类、分割算法不算提升精度,在 2017 年占比较高 的安防、视频广告、泛金融、手机及互联网娱乐领域之外,医疗影像、工业制造、 批发零售等现阶段的创新领域也将逐步解锁, 成为行业整体快速发展的重要支 撑。
    目前,市场上出现很多的计算机视觉科技公司,如下图所示:


    从整体上看,商汤技术的覆盖面最广,依图最少;但核心技术:人脸识别、 文字识别、图像识别、车辆识别、行人监测等技术三家公司都有
    从细分上看,只商汤拥有图像及视频编辑技术,且有深度学习框架;而旷视 的人脸技术在三家公司中最为完善,且拥有人体识别技术,能对手势进行识别;反之依图则拥有目标跟踪技术
    商汤,旷视,依图三家公司都在金融、安防领域中重点布局;在金融领域,旷视和商汤布局更深更广;而依图和旷视则在安防领域与公安紧密协作,且 旷视房地产安防上也有较深涉足
    商汤与手机厂商、运营商合作密切,未来大有借智能手机普及其人脸识别技术,成为最大的技术提供商,打造用户口碑,为将来打开 C 端开口树立品牌优势

    总结下来,计算机视觉巨头们都比较注重大公司的业务链,对于中小企业, 普通游客的人脸识别,情绪分类反而发力不足。
    1.2 项目意义正因为巨头们对普通用户,中小企业的情绪分类业务发力不足,我决定开始此处 情绪社区项目。
    一方面,中小企业,商场的视频监控流量巨大,同时人工处理十分低效且耗费人 力物力财力,另一方面,巨大的普通用户的的视频可以进行分类处理,激发普通用 户的分享欲望,可以搭建一个社区开发普通用户的分享乐趣,并以社区的形式,拥 有点评分享的功能。
    总结下来就是可以从以下几个角度阐释我们做这个项目的意义:

    从中小企业,商场,公共场所,人脸识别,情绪分类的需求很迫切;
    对于部分开发者来说,廉价合适的情绪分类 api 接口需求很大
    对于普通用户来说,情绪识别并分享(识别前后的)视频的乐趣很大,落地场景很多

    1.3 项目目标关于“情绪社区”这个项目,我们希望最终能做成一个线上平台,以各种形式开放 使用以提供服务,包括但不限于移动端设备应用、个人电脑软件应用、网站平台、公众号,微信小程序。为了能方便快捷地提供服务,多样全面的使用形式亦是这款产品 的一个亮点。
    最终将做成一个 B/S 框架app和微信小程序的人脸情绪识别app,并都拥有社区论坛功能的。同时将识别分类模型部署在服务器,可以提供给中小型企业 api。
    按照初期计划,我们希望达到的效果(可提供的服务)主要包括:

    对于中小企业,商场,公共场合,提供 CNN 模型 api 接口,以及技术支持
    对于部分开发者,我们提供 api 接口,处理视频,图像,json 形式返回处理后的结果
    对于普通用户,我们提供这款 app 的 web 端和微信小程序端,用户可以通过手机或者 pc 浏览 app,上传视频,返回情绪识别结果,并可以分享在 app 的 BBS 社区,同时可以发表评论与帖子

    2 功能需求描述2.1 系统角色
    管理员:视频信息审核用户资格审查论坛数据审查
    用户:用户注册与登录上传视频论坛社区分享 论坛社区评论 论坛社区发帖论坛社区管理板块 修改个人信息

    2.2 用户信息获取与维护2.2.1 功能说明初次注册,系统要求用户进行相关信息的填写,并记录至系统中。
    2.2.2 激励/响应序列
    刺激:用户注册或初次登录
    响应:给出信息填写要求
    刺激:用户选择答案
    响应:记录用户年龄等情况并给出对应论坛版块选择列表

    2.3 视频分析2.3.1 功能说明用户可进行上传视频和得到反馈结果。
    2.3.2 激励/响应序列
    刺激:用户选择上传视频功能
    响应:进入上传视频页面
    刺激:用户按下上传按钮,上传视频
    响应:提醒用户并生成结果
    刺激:用户按下其他按钮
    响应:进入其他页面

    2.4 社区论坛2.4.1 功能说明用户可以浏览论坛社区,或者分享视频,发布帖子,发表评论。
    2.4.2 激励/响应序列
    刺激:用户进入社区论坛
    响应:按一定顺序列出相关板块和帖子
    刺激:用户关键字搜索
    响应:给出板块或帖子中含有该关键字的搜索结果
    刺激:用户编写帖子或者评论
    响应:系统提示是否提交,更新页面以及相关数据

    2.5 用例图
    2.6 E-R 图
    2.7 系统流程图
    2.8 系统交互图
    2.9 概念类图和数据流图
    2.10 数据流图
    3 总体设计3.1 总体目标3.1.1 满足的需求满足的核心需求是:用户能够通过该平台上传视频得到系统分析的结果,同时可以在论坛社区分享评论发帖需求。
    3.1.2 技术基础与运行环境
    Web 端操作系统:Win95 以及以上版本
    微信小程序端:wechat 6.6.7 以及以上版本
    数据库:MySQL 数据库
    Web 框架:Django
    系统编写语言:Python
    深度学习平台:Keras, tensorflow

    3.2 系统总体结构对于用户来说,有如下系统功能:包括用户管理模块,用户视频情绪分析模块,用户论坛社区模块;对于管理员来说,主要是参与系统的管理与维护,审核相关信息。按照这几个准则将整个系统按照下图分为若干模块。

    3.3 各功能模块描述3.3.1 用户管理模块用户注册登录之后,系统会记录相关信息,同时可以修改个人信息,以及每次使用视频文件和社区之后,用户的管理模块的用户文件数据管理信息都会更新记录,同时也保留了管理员删除用户的权限,如果该用户有违法违规操作。
    3.3.2 用户视频情绪分析模块
    用户视频上传:用户点击上传视频按钮后,从文件夹打开选择的视频,上传系统,同时会检查视频格式,大小,分辨率,时长,对于不满足格式的视频,会弹窗相关信息
    算法模型分析:调用已经训练好了的 CNN 模型,将用户上传的视频切割成一帧一帧的图像,然后用模型先切割出人脸然后用模型对人脸表情进行 分类,然后把结果按照帧数打印成时序图写入 js 代码中,嵌入在 html 页面
    用户结果反馈:将嵌入结果时序图的 html 发送给用户,用户得到视频分析的结果

    3.3.3 用户社区模块
    版块管理:用户可以自设定一些版块,也可以提交举报或者删除,填写系统申请单,由后台审核之后会发布在系统之内
    帖子发布:用户可以自己在相应版块下申请发布帖子,按照系统格式,填写完毕,提交等待管理员审核
    跟帖,评论:用户可以在别人的帖子下选择“回复”来跟帖或者评论,帖子的底部有转发按钮,可以支持转发

    4 数据设计用户表

    视频表

    帖子信息表

    版块信息表

    5 算法主要是 CNN 深度学习算法。其他算法见源码。
    本次项目的基础模型是参考开源项目 Xception 框架设计而成。我们提出了一个用于设计实时 CNN 的通用卷积神经网络构建框架。我们通过创建一个实时视觉系统来验证我们的模型,该系统使用我们提出的 CNN 架构在一个混合步骤中同时完成人脸检测,性别分类和情感分类等任务。在介绍了培训程序设置的细节之后,我们继续评估标准基准组。我们报告 IMDB 性别数据集中 96%的准确率和 FER2013 情绪数据集中 66%的准确率。除此之外,我们还介绍了最近实时启用的反向传播可视化技术。引导式反向传播揭示了体重变化的动态变化并评估学习到的特征。我们认为,为了减少慢速性能和实时体系结构之间的差距,现代 CNN 体系结构的谨慎实施,当前正则化方法的使用和以前隐藏功能的可视化是必要的。我们的系统已通过部署在 RoboCup @ Home 比赛期间使用的 Care-O-bot 3 机器人进行验证。我们的所有代码,演示和预训练架构均已在我们公共存储库的开放源代码许可下发布。
    我们提出两种模型,我们根据他们的测试精度和参数数量进行评估。两种型号的设计思路都是在参数数量比率上创建最佳精度,减少参数数量有助于我们克服两个重要问题:

    首先,使用小型 CNN 可以缓解我们在硬件受限系统如机器人平台中的低速表现
    其次,参数的减少在奥卡姆剃刀架构下提供了更好的泛化

    我们的第一个模型依赖于消除完全相连的层,第二种架构将完全连接层的删除和深度方向可分离卷积和残留模块组合在一起,两种体系结构均使用 ADAM 优化器进行了培训。
    遵循先前的架构模式,我们的初始架构使用全局平均池来完全移除任何完全连接的层。这是通过在最后的卷积层中具有与类数量相同数量的特征图并且应 softmax 激活函数到每个缩小的特征地图。
    我们最初提出的架构是一个标准的全卷积神经网络,由 9 个卷积层 ReLUs ,Batch Normalization 和 Global Average Pooling 组成。该模型包含约 600,000 个参数。它在 IMDB 性别数据集上进行了训练,其中包含 460,723 个 RGB 图像,其中每个图像属于“女人”或“男人”类,并且在该数据集中达到了 96%的准确性。我们还在 FER-2013 数据集中验证该模型。该数据集包含 35,887 个灰度图像,其中每个图像属于以下类别之 一{“愤怒”,“厌恶”,“恐 惧”,“高兴”,“悲伤”,“惊讶”,“中立”}。
    我们的初始模型在这个数据集中达到了 66%的准确率,我们将此模型称为“顺序完全 CNN”。
    我们的第二个模型受到了 Xception 架构的启发。这种架构结合了残余模块 和深度智能可分离卷积的使用。剩余模块修改两个后续图层之间所需的映射,以便学习的特征成为原始特征映射和所需特征的差异。因此,为了解决更容易的学习问题 F(x),希望的特征 H(x)被修改,使得:
    H(x) = F(x) + x我们设计的基于 Xeception 的模型如下图:

    我们预测结果的热力图表示如下图:

    6 人机交互设计6.1 web 登录界面
    用户首先进入登录界面,如果没有注册过的用户就会跳转到注册界面,如果注册过的 普通用户就会跳转到主界面,管理员跳转到后台管理界面。
    6.2 web 注册界面
    注册界面会对输入进行检验,并弹窗提示。
    6.3 主界面
    主界面有多个跳转接口,可以跳转到任何一个位置,同时主界面会显示出最近 的帖子和热门帖子,点击帖子的链接可以跳到帖子的正文 html。同时在 page 上面有搜索引擎,可以支持全站搜索相关帖子,以及关键词。

    6.4 热门帖子界面
    显示最多点赞数的帖子,点击 readme 可以跳转到具体页面。
    6.5 发帖界面
    6.6 情绪分类界面
    首先是上传文件按钮,选择文件上传后,点击上传就可以把文件上传进服务 器,然后服务器运行算法模型分析每一帧图像的人脸以及情绪分类,并合成新的 视频文件,显示在本页面之间。同时,支持弹窗提示,提示不能传空。

    显示分析结果

    6.7 问答界面
    6.8 联系我们界面
    6.9 数据库界面

    7 总结本次项目是我一个人独立完成的,选题的立意来自自己寒假看的一篇关于 CNN 的论文,于是想着这学期做出一个情绪分类搭载论坛社区的系统。
    总的来说,自己按照软件工程书上的步骤,一步步每一个步骤每一个文档写下来,PPT 写了好几份,文档写了七八份,虽然很辛苦,但是也对软件工程的知识理解更加深厚了。
    首先,我先谈谈我对软件工程的理解。软件工程在我的脑海里就是如何利用工程化管理的技术 来做软件。为什么会诞生软件工程呢?随着代码量的增大,人对代码的掌控能力越来越弱, 代码的逻辑、进度和成本越来越不好控制,产生了软件危机!为了解决软件危机,软件工程 应运而生。
    在代码上,我在软件工程中学习到的是在细节上:

    第一、需要遵守代码规范,好处是便于修改和维护。让别人看的清楚你的代码
    第二、数据和业务逻辑的分离。我们需要将代码进行模块化,从而更好地维护和复用代码
    第三、懂得合理地设计接口,既不能面面俱到,也不能太过笼统,够用就好。比如说:链 表的接口设计和菜单的接口设计就有所不同。链表需要增删查改的接口,而菜单的接口就无 需如此太过细节化
    第四、非功能性需求,比如说安全性。这里尤其需要谈到的是线程安全,如何利用加锁的 机制构建出写出安全的代码
    第五、设计思想,这里需要应用一些前人总结的设计模式,比如说工场模式、观察者模式、 适配器模式等。应用这些模式能大大增加代码的延展性,更好地包容变化,更好地复用代码。 当然,为了拓展视野,老师也提到函数式、形式化方法的编程

    所以,总的来说,我觉得自己一个人在大学阶段独立完成软件工程项目还是很有意思且富有挑战的,对于以后就业来说,应该帮助很大的。
    2 评论 23 下载 2018-10-31 22:23:19 下载需要11点积分
  • 基于Java和Access数据库的飞机票订票系统

    一、课程设计目的
    通过实际的编程与学习,了解自己的学习情况和实际代码编辑的动手能力
    通过编程发现问题并解决问题,提高自己对程序代码的了解,解决问题的能力,以及动手操作能力
    通过编译代码,设计程序。熟悉 java 与SQL的编程过程与运用以及两种语言的链接。了解自己专业知识的运用
    通过这课程设计,知道自己专业知识的学习框架。对以后的工作更好的运用,更好的掌握专业技能

    二、 设计内容
    登陆界面:对于普通用户和管理员进行权限登陆,进行不同的权限授予
    普通用户界面:主要是进行航班查询和下订单等处理

    查询航班:用户可以对有需要的进行航班查询预订:用户可以在查询航班的界面直接预订,或者知道需要的航班号预订机票查询订单:用户可以通过已知订单号查询已下订订单退订:用户可以通过已知订单号退订已下订订单
    管理员界面:主要对用户已下订单的处理和处理航班等信息

    订单处理:查询出用户已下订单(包括所有状态的订单),然后对订单进行改签或删除处理查询航班:查询出现在正有效的航班,选择航班可以修改航班动态创建航班:创建新的航班删除航班:删除已处在的航班修改航班:修改一个已存在航班的信息

    三、需求分析3.1 系统的安全性系统运行安全是决定软件质量的重要因素,虽然此机票预订系统不需要接入Internet,但系统中涉及多方信息,如果有人蓄意破坏任意信息,都可能会导致系统的停用,会带来损失,因此仍然需要保证它的安全。为了保证系统的安全性,必须采取一定的安全措施,防止用户越权使用,防止工作数据被非法篡改、破坏和泄露等。既要考虑操作系统的安全性,还要考虑到本系统本身的安全性。所以首先运用数据库对于管理员、普通用户授予不同权限,各自进入自己相应的界面。
    3.2 系统的合理性在设计系统时要考虑实际的系统性能和硬件要求,不能忽视所处环境,也不能一味地追求新技术,要保证系统的合理性,使本系统能够在现流行的Windows XP和Window 7等系统中流畅运行。
    3.3 系统的简单性、易用性要考虑到不同用户的计算机操作水平,一般而言,大部分用户的计算机操作水平偏低,因此开发时要本着“简单易用”的原则,方便各层次人员的使用,使人员的培训降到最低。通过鼠标以及图标等按钮进行“傻瓜式”操作,简单明了,符合大众操作。
    3.4 系统的稳定性、可靠性、安全性订票人员来源广泛,分布性强,往往不具备专业的计算机知识,因此,本系统必须达到稳定、可靠、安全等要求。
    四、概要设计4.1 功能设计《网上机票预订系统》本是在Internet环境下运行的,但根据课程需求在此我们先将它做为一个c/s程序。该项软件开发的意图是为了方便航空公司进行乘客预定票的管理,减少管理中出现的麻烦,它主要在某一航空公司内部进行使用,再加之这是一项独立的软件,全部内容自含,所以不会涉及到与其它系统、产品的联系和接口问题。
    根据分析,机票预订系统系统模块如下图所示。

    4.2 数据字典数据字典是系统中各类数据描述的集合,是进行详细的数据的收集和数据分析所获得的主要成果。数据字典在数据库设计中占有很重要的地位。
    此系统数据字典部分如下:

    名字:旅客信息描述:旅客的个人信息,用于对旅客的确认定义:旅客信息=姓名+性别+工作单位+身份证号码+旅行时间+旅行目的地等等
    名字:航班信息描述:航班的起飞时间及上机时间等,让旅客能够查看和确认定义:航班信息=编号+终点+起飞始点等等
    名字:机票订单描述:旅客交付费用的凭证定义:机票账单=旅客姓名+交付费+时间等等
    名字:取票通知描述:旅客领取机票的凭证定义:取票通知=旅客姓名+领票时间
    名字:航空公司数据库信息描述:已订票的旅客在航空公司的记录和航班信息等等定义:航空公司数据库信息=航班机票信息+也订票旅客的信息等

    4.3 系统数据表下面将主要介绍关键数据表的数据库设计的详细说明。
    旅客信息系统的结构



    字段名
    数据类型
    长度
    约束
    描述




    passager name
    varchar
    50
    主键
    旅客姓名


    id
    decimal

    不为空
    证件号码


    telephone number
    decimal

    不为空
    联系方式


    sex
    varchar
    50
    不为空
    性别


    password
    Varchar
    20
    不为空
    密码


    power
    number

    不为空
    权限



    航班信息系统的结构



    字段名
    数据类型
    长度
    约束
    描述




    flight number
    decimal

    主键
    航班号


    take off place
    varchar
    50
    不为空
    起飞地


    destination
    varchar
    50
    不为空
    目的地


    flight time
    time

    不为空
    起飞时间


    BusyNumber
    decimal

    不为空
    商务舱数量


    CheapNumber
    decimal

    不为空
    经济舱数量


    ArriveTime
    time

    不为空
    到达时间


    Cprice
    int

    不为空
    经济舱价格


    Bpric
    int

    不为空
    商务舱价格


    FlightMove
    varchar
    100
    不为空
    航班动态


    FlightTime
    time

    不为空
    起飞日期



    取票通知单系统的结构



    字段名
    数据类型
    长度
    约束
    描述




    passager name
    varchar
    50
    主键
    旅客姓名


    get ticket time
    time

    不为空
    取票时间


    flight number
    decimal

    不为空
    航班号


    seat number
    decimal

    不为空
    座位号


    flight ticket type
    varchar
    50
    不为空
    机票类型


    OrderForm
    decimal

    自动编号
    订单号


    IfPay
    varchar
    100

    状态


    price
    decimal

    不为空
    价格



    银行用户表



    字段名
    数据类型
    长度
    约束
    描述




    Account
    varchar
    50
    不为空
    旅客姓名


    code
    time

    不为空
    取票时间


    passager name
    varchar
    50
    不为空
    旅客姓名



    4.4 E-R图介绍概念设计是一种面向对象的数据模型,是管理者观点使用自上向下方式来对数据和信息建模。它描述了从管理者角度看到的数据,它反映了用户的实现环境,这种方法用ER图描述现实世界中的实体,而不涉及这些实体在系统中的方法。概念设计中最著名的方法就是实体联系方法(ER方法),建立ER模型,用ER图表示概念结构,得到数据库的概念模型 [2]。
    ER模型中包含“实体”,“联系”和“属性”。在本系统中,多对多的关系用(m-n)表示。其各个实体ER图如下所示:
    旅客E-R图

    航班信息E-R图

    取票通知E-R图

    总体E-R图
    通过逻辑设计的目的是把概念设计好的概念模型转换成与数据模型相符合的逻辑结构。这些模型在功能上、完整性和一致性约束及数据库的可扩展性等方面均应满足用户的各种要求。因而,根据上节的实体E—R图,汇总成总体E—R图如下:

    4.5 系统流程图
    五、运行与调试普通用户注册


    登陆窗口


    航班查询界面

    查询到用户理想的航班后,点击航班,然后直接点击预订窗口

    订单查询


    用户可以在查询到的订单,然后取消订单

    在已知订单的情况下取消、增加订单


    用户输入银行卡账号密码支付


    管理员的界面

    查询用户提交的订单

    选择用户订单进行改签、删除处理


    查询航班、修改航班动态


    创建新的航班



    取消一个航班


    航班查询

    修改航班

    因为已存在用户订单,不能修改该航班信息

    数据库中不存在该航班,不能修改



    关于数据库的定义图片





    六、总结在课程设计的过程中,我学到了很多,也找到了自己身上的不足。感受良多,获益匪浅。我们分工合作、齐心协力,一起完成了课程设计前的准备工作(阅读课程设计相关文档)、小组讨论分工、完成系统开发的各个文档、课程设计总结报告、,个人小结的任务。在课程设计中我们便对这次任务进行了规划和分工。在设计中我们基本能按照规范的方法和步骤进行,首先对现有的系统进行调查,并查阅有关资料,最后确定设计方案,然后设计并制作,实施过程中我们深刻的认识到认真执行管理系统软件标准的重要性,由于我们对管理系统软件相关的标准和规范不太了解,缺少行为操作准则,所以在设计中手法比较生硬,主与次也没能很好把握住,这些方面通过这次的设计过程我们都要加强了解。我们组的成员一起努力,查阅资料、小组讨论、对资料进行分析,并在这段时间里完成了整个设计,并最后撰写课程设计报告及个人总结。
    1 评论 3 下载 2019-09-18 08:59:33 下载需要12点积分
  • 基于C++求解2N皇后问题

    一、算法思想首先分析一下 2N 皇后问题中的 N:

    当 N 为偶数时:其实只要求得一组可行解即可,另外一组可行解可以由当前解沿N*N 矩阵的中轴线作对称变换得到。因为 N 为偶数,所以不会存在黑白皇后位置冲突的情况。
    例如:N=4 时,求得一组可行解为:3 1 4 2,按着这个思路,变换得到另一组可行解为:2 4 1 3。可以判断,这样的两组解合并起来是符合题目要求的。
    当 N 为奇数时:沿中轴线对称的方式不再可行,因为肯定有一个皇后会落在中轴 线上。此时,可以考虑通过中心点作点对称的情况。
    这里要注意,如果求得的可行解存在关于中心点对称的皇后摆放(或有皇后位于中心点),那么此解不合要求,需要重新再求;直到没有两个皇后的位置是关于中心点对称,另 一组解可以通过对当前解关于中心点作点对称变换得到。
    例如,N=5 时,求得一组可行解为:2 4 1 3 5,按着这个思路,变换得到另一组可行解 为:1 3 5 2 4。可以判断,这样的两组解合并起来是符合题目要求的。

    从上可以看出,其实 2N 皇后问题在大多数情况下并不需要二次求解 N 皇后,只需求 得一组可行解即可。
    那么,接下来的事情就好办多了。只需要利用目标算法求得 N 皇后问题一个符合要求的解即可。
    爬山算法属于局部搜索算法的一份子,因此是一种解决最优化问题的启发式算法。在实际运用中,爬山算法不会前瞻与当前状态不直接相邻的状态,只会选择比当前状态价值更好的相邻状态,所以简单来说,爬山算法就是向价值增长方向持续移动的循环过程。初始状态下,每行每列都是一个皇后,之后的求解就是对存在冲突的列,寻找其他的冲突列来进行交换。因为寻找是随机的,所以每次程序的运行结果可能也存在一定的偶然误差。求解过程中,当得到了局部极大值时,如果不是全局最优解(即冲突数为 0),则随机生成初始状态,重新求解,直到得到全局最优解。
    CSP 算法的实现与爬山算法有不少的相同部分。比如初始值的生成,同样,也都是 采用交换列的方式来实现消解冲突的。求解时,遍历每一个皇后,选择当前行的皇后与其他皇后冲突最少的列(相同则随机选),交换当前行与目标行皇后。若遍历完后没求得解,则再遍历,直到求得解。
    二、算法的空间复杂度在实现 N 皇后问题求解的时候,我采用了大小为 N 的一维数组保存当前的皇后摆放状态,数组下标为当前皇后所在的行,数组元素的值即为当前皇后摆放的列。这样的做法将一个二维问题降到一维来存储,有效地节省了空间开销。
    由上面的算法思想分析可知:同一时刻,只有一组当前状态和一组相邻状态占用了空间。故算法的时间复杂度为 O(n)。
    三、算法的时间复杂度由于在随机重启爬山算法中,采用随机数来选定初始状态,初始状态中的冲突数为 O(N2)。程序的具体运行时间具有一定的随机性,因为只有正确的尝试才会使得冲突数减少。假定交换尝试的总次数为 M,M 的值具有较强的随机性,平均情况下的时间复杂度应该为 O(MN2)。
    CSP:初始状态中的冲突数为 O(N2),此后每次要交换时更新冲突数时为 4N=O(N)(求交换前两行冲突数及交换后两行冲突数)。遍历皇后 O(N),遍历总次数为 M,M 的值具有较强的随机性,故时间复杂度为 O(N2+MN2)=O(MN2)。
    四、实验结果说明我特意写了一份回溯法求解 N 皇后问题的程序,作为对比参照。
    下面是程序运行计时的结果对比:
    当 N=10 时
    回溯法求解 10 皇后问题

    爬山算法求解 10 皇后问题

    分析:N=10 的取值比较小,两种方法几乎都是瞬间完成了求解。
    把 N 再取得大一些
    回溯法求解 16 皇后问题

    爬山算法求解 20 皇后问题

    分析:此时就可以明显地看出差异了。N=16 时,回溯法求解就已经花费了 318 秒;而N=20 时,爬山算法的耗时也还在 1 秒以内。从这里就可以看出 AI 算法对程序运行效率的提升是相当惊人的。
    再取一些更大的 N 值来看看爬山算法程序的运行情况
    爬山算法求解 100 皇后问题

    爬山算法求解 300 皇后问题

    爬山算法求解 800 皇后问题

    爬山算法求解 1000 皇后问题

    最后,再来看一下 CSP 算法的求解效果:

    分析:从这里就可以很明显地看出 CSP 的算法运行效率要高于随机爬山算法。
    简单分析一下原因,两种算法的时间复杂度都为 O(MN2),但是:

    CSP 的 M 值要远远小于爬山算法的 M
    在实际的编写时,CSP 的交换尝试时间耗费为 4N=O(N),而爬山算法因为我维护了一个冲突列的容器,所以每次交换尝试的时间耗费都为 O(N2)
    1 评论 2 下载 2019-09-16 16:16:33 下载需要7点积分
  • 基于QT实现的旅游路线查询系统

    一、功能要求
    系统初始的城市总数不少于10个
    建立汽车、火车和飞机的时刻表(航班表),时刻表(航班表)中包含沿途到站及票价信息
    不能太简单(不能总只是1班车次相连),旅客的要求包括:起点、终点、途经某些城市和旅行策略
    旅行策略包括:

    最少费用策略:无时间限制,费用最少即可最少时间策略:无费用限制,时间最少即可限时最少费用策略:在规定的时间内所需费用最省
    旅行模拟查询系统以时间为轴向前推移,每10秒左右向前推进1个小时(非查询状态的请求不计时)
    不考虑城市内换乘交通工具所需时间,但是考虑因换乘交通工具产生的等待时间
    系统时间精确到小时,也就是正常时间的10秒钟
    建立日志文件,对旅客状态变化和键入等信息进行记录
    选做一:某旅客在旅行途中可更改旅行计划,系统应做相应的操作
    选做二:用图形绘制地图,并在地图上反映出旅客的旅行过程

    二、需求分析2.1 项目需求本次旅行模拟系统查询项目的基本需求是实现一个模拟旅行系统查询的功能。
    在基本功能上,如果是普通的旅行客户,需要实现用户信息的登录登出,对于没有注册过信息的新用户还需要提供进行旅客信息注册功能;用户输入旅行路线信息,包括起始站,终点站,以及旅客出发时间;旅客可以自行选择其中三种策略中的一种来定义出行方式;最后系统能够根据旅客输入路线信息以及选择的策略生成最佳的旅行路线,所给路线中需要包括出发地点,终止地点,出行时间,出行方式,以及途中的中间站,若需要更改出行交通工具,系统还必须要给出中间站的换乘方式;对于旅客当前的状态,系统需要能够每隔一定的实际输出当前旅客的状态信息,状态信息包括旅客的路线,旅客所乘坐的交通工具,旅行时间等等信息。
    对于登录的管理员,除了能够实现以上所述的客户的功能之外,另外还有一个就是能够文件处理功能,包括查询用户登录的信息、用户输入的路线信息、系统事件信息等。
    在模拟旅行查询系统的高阶需求方面,我们需要可视化的显示旅客当前的状态信息,比如如果旅客当前乘坐的是火车,并且正处于北京和上海之间,那么在图形化界面上就可以显示出一个正在运动的火车,而且火车的位置正处于北京和上海之间。图形化界面尽量做到简洁美观。
    另外一个就是,实际生活中旅客可能会在中途旅行过程中更改旅行计划,如果可以实现中途修改计划同时系统相应的计算出新的路线方式,则更是符合现实要求。
    2.2 项目业务要求
    2.3 问题整理
    呈现三种交通工具:汽车、火车、飞机
    某旅客于某一时刻向系统提出旅行要求,系统根据该旅客的要求为其设计一条旅行线路并输出
    系统能查询当前时刻旅客所处的地点和状态,包括旅客所停留城市,以及所乘坐的交通工具

    2.4 目标功能
    初始城市总数为11个
    分别建立汽车、火车和飞机的时刻表(航班表),通过文件读取信息初始化时刻表内容,有沿途到站、票价、路程等信息
    旅客的输入要求:起点、终点、途经城市,由用户自行选择旅行策略
    提供三种旅行策略:

    最少费用策略:无时间限制,费用最少即可最少时间策略:无费用限制,时间最少即可限时最少费用策略:在规定的时间内所需费用最省
    旅行模拟查询系统以时间为轴向前推移,打开可执行文件同时系统计时器开始工作,10秒代表1个小时向前推进(非查询状态的请求不计时);城市内换乘交通工具时间不予考虑,系统时间精确到小时
    建立日志文件,对旅客状态变化和键入等信息进行记录
    利用QT实现地图界面的可视化,在地图上实时反映出旅客当前的地理位置,交通工具,并且能够动态显示其行进过程

    三、模块划分
    3.1 主模块模块功能
    主模块负责接收键盘键入命令,包括用户的输入和管理员的输入,分析该命令并调用相应的子模块中的接口函数,并以系统时间为轴向前计时,推进运行。
    3.2 线路查找模块模块功能
    该模块主要负责根据用户输入的起止城市、旅行策略,生成符合条件的旅游线路,该模块是整个系统的核心功能模块。
    主要算法

    Dijkstra算法:求一个城市到其他所有城市的最短路径
    Floyd算法:求任意两个城市之间的最短路径

    算法思路
    根据初始化的文本数据,将读取文件每一个城市抽象为一个节点,生成一个交通路线图,抽象边长为票价/路程的值,前两种策略则根据Floyd算法计算出最短路径生成,第三种策略则是先以时间为权重求得所有路径,然后计算每一条路径的费用,有路径满足,输出,否则,返回“无法满足需求”。
    3.3 数据初始化模块模块功能
    该模块负责初始化载入已有的数据,包括交通工具的时刻表 / 航班表中的数据和登录账户的数据,便于系统的运行。
    编写思路
    建立时刻表、账户表的txt,通过行读取文件中的内容,初始化结构中的数据。
    3.4 状态记录模块模块功能
    该模块是系统负责对当前旅客的乘车状态(包括所选交通工具、乘车时间、票价)以及系统所键入信息的记录,便于管理员进行管理。
    编写思路
    计时器每十秒钟(代表系统一个小时)刷新一次记录,实时保存当前系统的所有运行数据。
    3.5 日志文件处理模块模块功能
    能够完成相应的对日志文件进行静态写入和查询结果输出操作的功能,方便管理员进行管理操作。
    编写思路
    打开状态记录日志文件,可以直接在日志上增添内容。
    3.6 图形化界面生成模块模块功能
    利用Qt开发框架编写可视化的界面地图,实时显示用户当前的乘车信息,动态的展示旅客的行进路线。
    编写思路
    参考相关Qt应用程序开发框架的专业书籍。
    四、结构定义4.1 枚举相关变量enum Vehicle{Bus = 1,Train = 2,Flight = 3};//枚举交通工具变量值enum Travel_Strategy{MinCost = 1, MinTime = 2, Min_Cost_Time = 3};//枚举旅行策略变量值enum Action{T_Login = 1, A_Login = 2, Travel = 3, Search = 4};//枚举发生事件行为变量值
    4.2 数据结构定义// 旅行计划表结构typedef struct{ int mean; //交通方式 int money; //该车次所需价格 int StartTime;//该车次起始时间 int EndTime; //该车次到达时间 int Time; //该车运行时间}TIME;// 城市结点结构typedef struct { TIME Time[30];//一天最多一条路线十趟车,包含起始时间与到达时间 int i; //路线个数}Path;// 交通图数据结构typedef struct { Path P[NN][NN];}Graph;// 交通图边的结构typedef pair <int,TIME> Road;// 旅行路线结构typedef struct{ int z; string s; vector<Road> r;}Travel;
    4.3 配置文件定义4.3.1 时间表(航班表)从左到右数据依次表示:
    起始城市、终点城市、路线价格、出发时间、到达时间
    (为了简便表示,我们在读取数据时用字母代替城市)哈尔滨(A) 北京(B) 上海(C) 广州(D) 武汉(E) 成都(F) 拉萨(G) 乌鲁木齐(H) 西宁(I) 福州(J) 重庆(K)

    4.3.2 密码文本(航班表)
    第一行代表数据库中存入的用户信息的账号,第二行是账户密码,第三行是用户的身份信息,user代表是普通旅客,admin代表是管理员。
    4.3.3 日志文件
    日志文件中包括事件发生的系统时间,余下一行是时间的类型,比如截图所示有“用户到来”、“管理员到来”、“用户注册”、“管理员注册”以及输出旅客查询的信息输出等。
    五、接口函数以及类定义Jmlog.h
    void searchlog(string a,string b,int c);void jmclear();void usercome(string a,int c,int b);
    add.h
    class add;}class add : public QDialog{ Q_OBJECTpublic: explicit add(QWidget *parent = 0); ~add();private slots: void on_pushButton_clicked(); void on_pushButton_2_clicked();private: Ui::add *ui;};
    Administrators.h
    namespace Ui {class administrators;}class administrators : public QDialog{ Q_OBJECTpublic: explicit administrators(QWidget *parent = 0); ~administrators(); void MIMA(QString,QString); void Open();private slots: void on_pushButton_clicked(); void on_pushButton_2_clicked();private: Ui::administrators *ui;};
    Chenggong.h
    namespace Ui {class chenggong;}class chenggong : public QDialog{ Q_OBJECTpublic: explicit chenggong(QWidget *parent = 0); ~chenggong();private: Ui::chenggong *ui;};
    Global.h
    extern Graph g;extern vector<Travel> TR;
    Graph.h
    typedef struct{ int mean;//交通方式 int money;//该车次所需价格 int StartTime;//该车次起始时间 int EndTime;//该车次到达时间 int Time;//该车运行时间}TIME;typedef struct { TIME Time[30];//一天最多一条路线十趟车,包含起始时间与到达时间 int i;//路线个数}Path;typedef struct { Path P[NN][NN];}Graph;typedef pair <int,TIME> Road;typedef pair <int,string> TB;typedef pair <TB,vector<Road> > Travel;
    Init.h
    int ToInt(char s[10]);void Print(Graph g);void Add(void);Graph Read(void);
    Login.h
    namespace Ui {class login;}class login : public QDialog{ Q_OBJECTpublic: explicit login(QWidget *parent = 0); ~login();protected: void timerEvent(QTimerEvent * event);private slots: void on_denglu_clicked(); void on_close_clicked(); void on_zhuce_clicked();private: Ui::login *ui; int id1;};
    Luxian.h
    namespace Ui {class luxian;}class luxian : public QDialog{ Q_OBJECTpublic: explicit luxian(QWidget *parent = 0); ~luxian(); void Print(QString s);private: Ui::luxian *ui;};
    Plan.h
    extern int t;extern int t1;bool fn(TIME a, TIME b);int minDistance(int dist[], bool sptSet[]);int Low_T(vector<Road> line);TIME my_min(Path p, int preT);TIME my_min_lim(Path p, int preT, int limit);vector<Road> dijkstraCost(Graph graph, int src, int dst);Travel pivot_inT(Graph graph, vector<int>p, int T,string &s);vector<Road> dijkstraTime(Graph graph, int src, int dst, int T);vector<Road> dijkstraCost_T(Graph graph,int src,int dst,int T,int L);Travel pivot_inW(Graph graph, vector<int>p,string &s);Travel pivot_in_limit(Graph graph,vector<int>p,int T,int L,string&s);string Changecity(int a);string Changetime(int m);int Backcity(QString s);int Backtime(QString s);
    Search.h
    namespace Ui {class searcha;}extern int t;class searcha : public QDialog{ Q_OBJECTpublic: explicit searcha(QWidget *parent = 0); ~searcha();private slots: void on_pushButton_2_clicked(); void on_pushButton_clicked(); void on_pushButton_3_clicked();private: Ui::searcha *ui;};
    Users.h
    namespace Ui {class Users;}class Users : public QDialog{ Q_OBJECTpublic: explicit Users(QWidget *parent = 0); ~Users(); void MIMA(QString,QString);private slots: void on_pushButton_clicked(); void on_queding_clicked();protected: void timerEvent(QTimerEvent *event);private: Ui::Users *ui; int id1;};
    Watch.h
    extern int t;//系统时间extern string name;//用户名namespace Ui {class watch;}class watch : public QDialog{ Q_OBJECTpublic: explicit watch(QWidget *parent = 0); ~watch();protected: void timerEvent(QTimerEvent * event); void paintEvent(QPaintEvent * event); void mousePressEvent(QMouseEvent *e);private: Ui::watch *ui; int id2; QPixmap *pix;};void coordinate(int t,int &m,int &n);void change(int a,int &m,int &n);
    Wrong.h
    namespace Ui {class wrong;}class wrong : public QDialog{ Q_OBJECTpublic: explicit wrong(QWidget *parent = 0); ~wrong();private: Ui::wrong *ui;};
    Zhanghu.h
    extern int t;void write(string a,string b,string c);int judge(string a,string b,string c);
    Zhuce.h
    namespace Ui {class zhuce;}class zhuce : public QDialog{ Q_OBJECTpublic: explicit zhuce(QWidget *parent = 0); ~zhuce();private: Ui::zhuce *ui;};
    六、核心算法描述6.1 程序流程图
    6.2 费用最少策略以费用为权值,使用dijkstra算法寻找从出发点到其余点的最短路径,并在寻找过程中保存每一点的前驱,寻找完成后,通过前驱记录,构建出由源点到终点的路径。
    6.3 时间最少策略以时间为权值,使用dijkstra算法寻找从出发点到其余点的最短路径,并在寻找过程中保存每一点的前驱,寻找完成后,通过前驱记录,构建出由源点到终点的路径。
    6.4 限时费用最少基于时间最短策略求得的最短时间T,先对限制时间t进行判断,若满足T <= t,则以时间和费用为权值,分段寻找最短短路径,否则给出给出时间最少策略的路径。
    七、测试7.1 范例信息
    旅客信息

    账号:12345678密码:12345678路线:北京——广州旅客出发时间:1点途径城市:上海、武汉策略:最短时间策略
    管理员信息

    账号:12345678 密码:12345678执行操作:查看日志信息、观察用户状态、添加路线信息,检查添加路线信息路线添加详细信息:
    起始地点:重庆——福州交通方式:火车(用“1”代替)起始时间:2点终止时间:23点价格:876元


    7.2 测试截图7.2.1 普通旅客登录注册用户信息,注册成功,点击登录按钮,登录成功。

    输入路线信息,北京作为起始站,终止站为广州,设置武汉、上海为途径城市,选择最短时间策略。

    路线信息中包含中转信息,包括中转站点,交通方式,起始时间和终止时间,路线保存在日志文件中。

    如下图所示,用火车图案代表乘火车,飞机图案代表乘飞机,汽车图案代表乘坐汽车,将路线结果展示在图形界面中。

    7.2.2 管理员登录管理员直接注册账号后进行登录。

    右边的文本框显示旅客操作的信息,包括登录信息、旅行计划信息等,用下拉可以看清所有结果。

    观察用户状态和之前截图所示的一样,动态显示出当前用户的旅行计划状态,在图形化界面上显示。

    在输入框中输入需要添加的路线信息,包括起止时间,起止站点,交通方式,以及旅行价格,点击确认后提示成功。

    添加信息结构位于数据中的最后一排,根据如图所示,添加路线信息成功,如有不合适,可以直接删除。

    7.3 结果分析根据以上的程序执行结果的截图,整个程序执行期间没有出现停机状态,说明健壮性良好;根据用户的输入结果,程序可以输出相应的路线信息,经过线下按照实际录入信息的数据计算比对,策略吻合程度较高,基本满足算法正确性的要求;程序可以准确的记录下程序运行期间所发生的事件,通过添加路线的功能,管理员能够实时更新路线信息,更加符合实际程序运行的需要;图形界面显示方面,虽然没有能够实现很完美的表现用户状态很清晰的实时显示,不过基本的动态效果可以实现,能够将文字化的路线信息转成图形化表示。
    2 评论 9 下载 2019-05-08 10:33:58 下载需要15点积分
显示 15 到 30 ,共 15 条
eject