目录
项目一:中国计算机设计大赛赛事统计
一、问题描述
参加计算机设计大赛的n个学校编号为1n,赛事分成m个项目,项目的编号为1m.比赛获奖按照得分降序,取前三名,写一个统计程序产生各种成绩单和得分报表。
1.基本要求
1)每个比赛项目至少有10支参赛队;每个学校最多有6支队伍参赛;
2)能统计各学校的总分;
3)可以按照学校编号或名称查询,学校的总分、各项目的总分排序输出;
4)可以按学校编号查询学校某个项目的获奖情况;可以按项目编号查询取得前三名的学校;
5)数据存入文件并能随时查询
2.设计要求
1)输入数据形式和范围:可以输入学校的名称,赛事项目的名称。
2)输出形式:有中文提示,各学校分数为整数
3)界面要求:交互设计要合理,每个功能可以设立菜单,根据提示,完成相关功能的要求。
4)存储结构:学生自己根据系统功能要求自己设计,但是赛事相关数据要存储在文件中。
3.测试数据
要求使用全部合法数据,整体非法数据,局部非法数据。进行程序测试,以保证程序的稳定。
4.实现提示
假设3<赛事项目数量<=10,学校名称长度不超过20个字符。每个赛事结束时,将其编号、名称输入,并依次输入参赛学校编号、学校名称和成绩。
二、问题分析和任务定义
问题分析
设计一个中国计算机设计大赛赛事系统,可以输入相关信息后依照用户需求进行相关的查询,还具有存储功能将录入的信息保存下来以供查询。
注意以下几点:
1.3<赛事项目数量<=10,并且每个比赛项目至少有10支参赛队;每个学校最多有6支队伍参赛,输入时需要注意;
2.学校名称长度不超过20个字符;
3.输出形式:有中文提示,各学校分数为整数;
4.每个学校每个参赛队伍只能参加一个赛事项目;
任务定义
1.成绩的录入需要我们依照设置的提示来输入相关的数据;
2.自定义一个交互式的菜单,实现以下功能:
1)统计各个学校的总分;
2)按照学校编号排序输出;
3)按照总分排序输出;
4)按照各项目总分排序输出;
5)根据学校编号查询某个项目的获奖情况。
6)根据项目编号查询取得前三名的学校
7)数据存入文件并能随时查询
三、逻辑设计
1.数据类型
需要设置两个结构体,学校的结构体与比赛项目的结构体;
学校:学校id,学校名称,学校总分,学校在各项目里的总分,比赛项目数组
比赛项目:项目id,项目名称,参加该项目的队伍,分数数组,名次数组
typedef struct
{
int pro_id;//项目id
char pro_name[20];//项目名称
int pro_team;//参加该项目的队伍数量
int score[6];//获得的分数
int rank[6];//获得的名次
}Project;
typedef struct
{
int sch_id;//学校id
char sch_name[20];//学校名称
int all_score;//学校总分
int pro_score[pro_maxnum];//学校在各项目里的总分
Project p[pro_maxnum];//比赛项目数组
}School;
2.主要模块
初始界面及赛事系统信息读入:初始的界面设计,读入学校数量与比赛项目数量,并进行相关初始化;
主菜单界面:根据菜单提示,选择相应的算法来完成功能的实现;
输入操作:读入相关数据,如某学校在某项目中参与了几支队伍,都取得了什么名次;
排序输出算法:分为按学校编号排序输出,按学校总分排序输出,按各项目总分排序输出;
查询算法:分为按学校编号查询,按项目编号查询;
信息存储与读入算法:保证信息可存到本地并且可以读入。
函数 | 功能 |
---|---|
void init() | 初始界面及赛事系统信息读入 |
void menu() | 主菜单 |
void input() | 输入信息 |
void base_input() | 编号与名称的读入 |
bool is_true() | 检验信息输入是否符合规定 |
void all_score() | 统计各个学校的总分 |
void sort_out() | 排序输出 |
void id_out() | 按学校编号排序 |
void score_out() | 按学校总分排序 |
void pro_out() | 按各项目总分排序 |
void seek() | 信息查询 |
void id_seek() | 按学校编号查询某个项目的获奖情况 |
void pro_seek() | 按项目编号查询取得前三名的学校 |
void save_tofile() | 数据存入文件 |
void read_fromfile() | 从文件里读取数据 |
四、物理设计
给出数据结构及主要函数。
typedef struct
{
int sch_id;//学校id
char sch_name[20];//学校名称
int all_score;//学校总分
int pro_score[pro_maxnum];//学校在各项目里的总分
Project p[pro_maxnum];//比赛项目数组
}School;
typedef struct
{
int pro_id;//项目id
char pro_name[20];//项目名称
int pro_team;//参加该项目的队伍数量
int score[6];//获得的分数
int rank[6];//获得的名次
}Project;
void init()
{
cout << "*****************************************************************************************************************" << endl;
cout << "*** 欢迎使用中国计算机设计大赛赛事统计系统! ***" << endl;
cout << "*****************************************************************************************************************" << endl;
cout << "请您先输入大赛主要信息!" << endl;
while (true)
{
bool flag1 = false;
bool flag2 = false;
cout << "学校个数:";
cin >> sch_num;
cout << "项目个数:";
cin >> pro_num;
if (sch_num >= 1 && sch_num <= 20)
flag1 = true;
if (pro_num > 3 && pro_num <= 10)
flag2 = true;
if (flag1 && flag2)
{
for (int i = 0; i < sch_num; i++)
{
s[i].all_score = 0;
for (int j = 0; j < pro_num; j++)
{
s[i].pro_score[j] = 0;
}
}
return;
}
else cout << "您输入的信息有误!请重新输入!" << endl;
}
}
void menu()
{
int ord;
while (true)
{
cout << "*****************************************************************************************************************" << endl;
cout << "*** 您可以输入相应序号来提交请求! ***" << endl;
cout << "*** 【1】信息录入 ***" << endl;
cout << "*** 【2】各参赛院校总分 ***" << endl;
cout << "*** 【3】排序输出 ***" << endl;
cout << "*** 【4】信息查询 ***" << endl;
cout << "*** 【0】退出系统 ***" << endl;
cout << "*****************************************************************************************************************" << endl;
cin >> ord;
switch (ord)
{
case 1:
input();
break;
case 2:
all_score();
break;
case 3:
sort_out();
break;
case 4:
seek();
break;
case 0:
cout << "感谢您的使用!" << endl;
return;
default: cout << "您的请求有误!请您重新输入!" << endl;
}
}
}
void input()
{
base_input();
cout << "**************************************************" << endl;
do
{
for (int i = 0; i < sch_num; i++)
{
for (int j = 0; j < pro_num; j++)
{
cout << "请输入" << s[i].sch_name << "参加" << s[i].p[j].pro_name << "的队伍个数:";
cin >> s[i].p[j].pro_team;
if (s[i].p[j].pro_team)
{
cout << "请输入各队伍的排名:";
for (int k = 0; k < s[i].p[j].pro_team; k++)
{
cin >> s[i].p[j].rank[k];
switch (s[i].p[j].rank[k])
{
case 0:
s[i].p[j].score[k] = 0;
break;
case 1:
s[i].p[j].score[k] = 5;
break;
case 2:
s[i].p[j].score[k] = 3;
break;
case 3:
s[i].p[j].score[k] = 2;
break;
}
s[i].all_score += s[i].p[j].score[k];
s[i].pro_score[j] += s[i].p[j].score[k];
}
}
cout << "**************************************************" << endl;
}
}
} while (!is_true());
savetofile();
}
bool is_true()
{
bool flag = true;
//每个学校最多有六支队伍
for (int i = 0; i < sch_num; i++)
{
int cnt1 = 0;
for (int j = 0; j < pro_num; j++)
{
cnt1 += s[i].p[j].pro_team;
if (cnt1 > 6) flag = false;
}
}
//每个项目至少有十个队伍参加
for (int i = 0; i < pro_num; i++)
{
int cnt2 = 0;
for (int j = 0; j < sch_num; j++)
{
cnt2 += s[j].p[i].pro_team;
}
if (cnt2 < 10) flag = false;
}
if (flag) return true;
cout << "您输入的信息有误!!!" << endl;
cout << "请注意!每个学校最多有六支队伍参赛,且每个项目至少有10支队伍参加!" << endl;
cout << "**************************************************" << endl;
return false;
}
void all_score()
{
cout << "id:" << '\t' << "名称:" << '\t' << "总分:" << endl;
for (int i = 0; i < sch_num; i++)
{
cout << s[i].sch_id << '\t' << s[i].sch_name << '\t' << s[i].all_score << endl;
}
}
void sort_out()
{
int ord;
while (true)
{
cout << "*****************************************************************************************************************" << endl;
cout << "*** 您可以输入相应序号来提交请求!输入-1返回主菜单 ***" << endl;
cout << "*** 【1】按学校编号输出 ***" << endl;
cout << "*** 【2】按学校总分输出 ***" << endl;
cout << "*** 【3】按各项目总分输出 ***" << endl;
cout << "*****************************************************************************************************************" << endl;
cin >> ord;
switch (ord)
{
case 1:
id_out();
break;
case 2:
score_out();
break;
case 3:
pro_out();
break;
case -1:
return;
default: cout << "您的请求有误!请您重新输入!" << endl;
}
}
}
void seek()
{
int ord;
while (true)
{
cout << "*****************************************************************************************************************" << endl;
cout << "*** 您可以输入相应序号来提交请求!输入-1返回主菜单 ***" << endl;
cout << "*** 【1】按学校编号查询 ***" << endl;
cout << "*** 【2】按项目编号查询 ***" << endl;
cout << "*****************************************************************************************************************" << endl;
cin >> ord;
switch (ord)
{
case 1:
id_seek();
break;
case 2:
pro_seek();
break;
case -1:
return;
default: cout << "您的请求有误!请您重新输入!" << endl;
}
}
}
项目二:校园导游咨询
一、问题描述
设计一个校园导游程序,为来访的客人提供各种信息查询服务。
1.基本要求
(1) 设计你所在学校的校园平面图,所含景点不少于10个.以图中顶点表示校内各景点,存放景点名称、代号、简介 等信息;以边表示路径,存放路径长度等相关信息。
(2) 为来访客人提供图中任意景点相关信息的查询。
(3) 为来访客人提供图中任意景点的问路查询,即查询任意两个景点之间的一条最短的简单路径。
2.测试数据
以江苏科技大学长山校区为例.
3.实现提示
一般情况下,校园的道路是双向通行的,可设校园平面图是一个无向网,顶点和边均含有相关信息。
二、问题分析和任务定义
问题分析
设计一个江科大校园导游系统,可以依照用户的选择进行相关功能的实现,如查询景点信息,找到最短路径。
注意以下几点:
1.设置的时候注意景点不小于10个;
2.由于道路是双向的,因此构造无向图;
3.用Dijkstra算法解决最短路径问题。
任务定义
1.设置景点,路径相关信息,构成无向图;
2.提供校园平面图;
3.提供景点相关信息查询;
4.提供问路查询,即找到最短路径。
三、逻辑设计
1.数据类型
设置两个结构体,一个是Vertex,包括景点信息,表示点,另一个是MGraph,包括点与景点路径,表示图。
typedef struct {
int id;//景点代号
char name[N];//景点名称
char syn[N];//景点简介
}Vertex;
typedef struct {
Vertex vertex[max_vertices];//开个数组,存放景点信息
int edges[max_vertices][max_vertices];//路径
int vertex_num, edge_num;//图的顶点数和边数,也就是景点与路径
}Graph;
2.主要模块
-
初始化图上相关信息:包括景点信息,景点路径,景点个数,路径个数;
注意!景点路径为虚拟设置,与实际路径不符!!!
-
主菜单:根据不同的请求调用相关函数;
-
查询校园平面图:把所有景点输出;
-
查询景点详细信息:包括代号,名字,简介;
-
查询最短路径;
函数 | 功能 |
---|---|
void init() | 初始化 |
void menu() | 主菜单 |
void plane_figure() | 查询校园景点平面图 |
void spot_info() | 查询景点信息 |
void short_path() | 查询最短路 |
void dijkstra(int sta, int fin) | 计算最短路径及最短路径距离 |
四、物理设计
关键在于最短路算法的编写:
1.首先开四个数组:
int dist[max_vertices];//存储到起点的最短距离
bool st[max_vertices];//表示该点到起点的最短距离是否确定
int pre[max_vertices];//存储点的前趋点
int path[max_vertices];//存储最短路径
2.dist数组初始化为N,st数组初始化为false,pre数组各个点的前趋点初始化为自身;
3.dist[sta]为0,表示到起点自身的距离为0;
4.存在G.vertex_num个点,就迭代G.vertex_num次,每次从所有未确定最短距离的点里找到离起点最近的点,用该点来更新所有点的最短距离;
5.如果dist[fin]为N,则表示起点与终点之间没有连通的路径,若不为N,则最短路径长度为dist[fin];
6.利用一个while循环来把前趋点挨个存到path数组里,别忘了起点与终点也放进去,然后把path数组反转一下即为最短路径。
void dijkstra(int sta, int fin)
{
int dist[max_vertices];
bool st[max_vertices];
int pre[max_vertices];
int path[max_vertices];
for (int i = 0; i < G.vertex_num; i++)
{
dist[i] = N;
st[i] = false;
pre[i] = i;
}
dist[sta] = 0;
for (int i = 0; i < G.vertex_num; i++)
{
int t = -1;
for (int j = 0; j < G.vertex_num; j++)
{
if (!st[j] && (t == -1 || dist[j] < dist[t]))
t = j;
}
st[t] = true;
for (int j = 0; j < G.vertex_num; j++)
{
if (dist[t] + G.edges[t][j] < dist[j])
{
dist[j] = dist[t] + G.edges[t][j];
pre[j] = t;
}
}
}
if (dist[fin] == N)
{
cout << "两景点之间没有连通的路径!" << endl;
return;
}
int total = 1, x = fin;
path[0] = fin;
while (pre[x] != sta)
{
path[total++] = pre[x];
x = pre[x];
}
path[total++] = sta;
reverse(path, path + total);
printf("从%s到%s的最短路径为:\n", G.vertex[sta].name, G.vertex[fin].name);
cout << G.vertex[path[0]].name;
for (int i = 1; i < total; i++)
{
cout << "->" << G.vertex[path[i]].name;
}
cout << endl;
printf("从%s到%s的最短路径距离为:%d\n", G.vertex[sta].name, G.vertex[fin].name, dist[fin]);
}
项目三:算术表达式求解
一、问题描述
设计一个简单的算术表达式计算器。
1.基本要求
实现标准整数类型的四则运算表达式的求值(包含括号,可多层嵌入)。
2.测试数据
(30+270)/3-123
5+(9*(62-37)+15)*6
要求自行设计非法表达式,进行程序测试,以保证程序的稳定运行。
3.实现提示
可以设计以下辅助函数:
status isNumber(char ReadInChar); //视ReadInchar 是否是数字而返回 TRUE 或 FALSE 。
int TurnToInteger(char IntChar); // 将字符’0’.’9’ 转换为整数 9。
二、问题分析和任务定义
1.问题分析
由于不同的运算符具有不同的优先级,还要考虑是否存在括号,算术表达式的求值不可能总是从左到右进行,要借助栈实现;
注意以下几点:
1.非法表达式错误形式多样,需要尽可能考虑周全;
2.题目中对于空格没有要求,因此我们设置的时候可以遇到空格跳过,也就是说空格不算非法字符,用户输入的时候可以输入空格。
2.任务定义
1.设计一个简单的算术表达式计算器,可以实现标准整数类型的四则运算表达式的求值(包含括号,可多层嵌入);
2.运算式要进行检查,若为非法则不进行计算,要求重新输入正确的运算式;
三、逻辑设计
1.数据类型
1)数据结构
设置两个栈,一个存放运算符,另一个存放操作数。
stack<double> num_stack;//用于存放操作数;
stack<char> ope_stack;//用于存放运算符;
2)基本操作
push(); //向栈顶添加元素
pop(); //从栈顶移除第一个元素
top(); //返回栈顶元素
empty(); //判断堆栈是否为空
size(); //返回栈的大小
2.主要模块
- 检验字符串是否合法;
- 检验字符是否为操作数;
- 进行操作数栈两个数的+,-,*,/,并把结果放到操作数栈;
- 从左向右扫描字符串。
函数 | 功能 |
---|---|
bool is_true() | 检验字符串是否合法 |
bool is_number() | 该字符是否为操作数 |
void eval() | 进行操作数栈两个数的+,-,*,/,并把结果放到操作数栈 |
double scan() | 从左向右扫描字符串 |
四、物理设计
两个核心关键点:
1.双栈,一个操作数栈,一个运算符栈;
2.运算符优先级,栈顶运算符和即将入栈的运算符的优先级比较:
(1)如果栈顶的运算符优先级低,新运算符直接入栈
(2)如果栈顶的运算符优先级高或者优先级相等,先出栈计算,新运算符再入栈
算法流程:
1.检验字符串是否合法;
2.从左到右依次扫描字符串:
1)若为操作数则放到操作数栈;
2)若为’('直接入运算符栈;
3)若为’)‘则依次出运算符栈,直到栈顶为’)‘,把’)'也出栈;
4)若为其他运算符,根据优先级进行不同的操作:若栈顶优先级大于等于即将入栈的运算符优先级,则先出栈计算,新运算符再入 栈,否则新运算符直接入栈;
3.若运算符栈里还有运算符,则依次出栈;
4.最后操作符栈顶元素即为运算结果。
void evel()
{
double a = num_stack.top();//第一个操作数
num_stack.pop();
double b = num_stack.top();//第二个操作数
num_stack.pop();
char p = ope_stack.top();//运算符
ope_stack.pop();
double r = 0;//结果
//计算结果
if (p == '+') r = b + a;
if (p == '-') r = b - a;
if (p == '*') r = b * a;
if (p == '/') r = b / a;
num_stack.push(r);//运算结果放到操作数栈
}
double scan(string s)
{
for (int i = 0; i < s.size(); i++)
{
if (s[i] == ' ') continue;
if (is_number(s[i]))//操作数
{
int x = 0, j = i;//计算数字
while (j < s.size() && is_number(s[j]))
{
x = x * 10 + s[j] - '0';
j++;
}
num_stack.push(x);//数字入栈
i = j - 1;//后退一位,之后会++
}
else if (s[i] == '(') ope_stack.push(s[i]);//遇到'('直接入栈
else if (s[i] == ')')//遇到')'则一直弹栈
{
while (ope_stack.top() != '(')
evel();
ope_stack.pop();//把'('弹栈
}
else
{
while (ope_stack.size() && h[ope_stack.top()] >= h[s[i]])//栈顶运算符优先级大于等于新的运算符
evel();//则不断弹栈
ope_stack.push(s[i]);//把新的运算符放进栈里
}
}
while (ope_stack.size()) evel();//如果运算符栈里还有运算符,则不断弹栈
return num_stack.top();//栈顶操作数即为运算结果
}
bool is_true(string s) {
if (!is_number(s[0]) && s[0] != '(') {
cout << "输入错误!表达式开头必须是数字或者'('!" << endl;
return false;
}
if (!is_number(s[s.size() - 1]) && s[s.size() - 1] != ')') {
cout << "输入错误!表达式结尾必须是数字或者')'!" << endl;
return false;
}
int cnt1 = 0, cnt2 = 0;
bool flag = false;
for (int i = 0; i < s.size(); i++)
{
if (s[i] == ' ') continue;
if (!is_number(s[i]) && !is_ope(s[i]) && s[i] != '(' && s[i] != ')') {
cout << "表达式错误!表达式里存在非法字符!" << endl;
return false;
}
if (s[i] == ')' && !flag) {
cout << "表达式错误!右括号出现在左括号之前!" << endl;
return false;
}
if (s[i] == ')' && s[i + 1] == '(') {
cout << "表达式错误!两个括号之间要有运算符!" << endl;
}
if (is_ope(s[i]) && is_ope(s[i + 1])) {
cout << "表达式错误!运算符后面不能为运算符!" << endl;
return false;
}
if (s[i] == '/' && s[i + 1] == '0') {
cout << "表达式错误!除数不能为0!" << endl;
return false;
}
if (s[i] == '(') flag = true, cnt1++;
if (s[i] == ')') cnt2++;
}
if (cnt1 != cnt2)
{
cout << "表达式错误!左右括号不匹配!";
cout << cnt1 << " " << cnt2 << endl;
return false;
}
return true;
}