PTA题目集4~6的总结
Posted cbyblogs
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了PTA题目集4~6的总结相关的知识,希望对你有一定的参考价值。
1.前言
- 题目集4
题目集4题目量适中,整体难度中偏易
题目7-1要求厘清类与类间的关系,能对题目所给的要求作出准确的设计,难度中偏上
题目7-2~7-7考察基本的算法,对Java中集合框架的使用以及对LocalDate类的使用,总体上难度偏易
- 题目集5
题目集5题目量适中,整体难度偏易
题目7-1,7-3,7-4考察对正则表达式的使用,难度偏易
题目7-2考察基本的算法(冒泡排序)
题目7-5,7-6以两种不同的聚合结构重写日期问题,但由于给出了类图,只需根据类图完成算法填空即可,难度中偏易。
- 题目集6
题目集6只有一题,题目量少但难度较高
题目7-1是对题目集4中的计价程序进行迭代,增加了 桌号、菜单订单顺序颠倒、不符合格式的输入、序号重复等各种输入错误情况
2.设计与分析
OOP训练集4
7-1菜单计价程序-3
设计点菜计价程序,根据输入的信息,计算并输出总价格。
输入内容按先后顺序包括两部分:菜单、订单,最后以"end"结束。
菜单由一条或多条菜品记录组成,每条记录一行
每条菜品记录包含:菜名、基础价格 两个信息。
订单分:桌号标识、点菜记录和删除信息、代点菜信息。每一类信息都可包含一条或多条记录,每条记录一行或多行。
桌号标识独占一行,包含两个信息:桌号、时间。
桌号以下的所有记录都是本桌的记录,直至下一个桌号标识。
点菜记录包含:序号、菜名、份额、份数。份额可选项包括:1、2、3,分别代表小、中、大份。
不同份额菜价的计算方法:小份菜的价格=菜品的基础价格。中份菜的价格=菜品的基础价格1.5。小份菜的价格=菜品的基础价格2。如果计算出现小数,按四舍五入的规则进行处理。
删除记录格式:序号 delete
标识删除对应序号的那条点菜记录。
如果序号不对,输出"delete error"
代点菜信息包含:桌号 序号 菜品名称 份额 分数
代点菜是当前桌为另外一桌点菜,信息中的桌号是另一桌的桌号,带点菜的价格计算在当前这一桌。
程序最后按输入的先后顺序依次输出每一桌的总价(注意:由于有代点菜的功能,总价不一定等于当前桌上的菜的价格之和)。
每桌的总价等于那一桌所有菜的价格之和乘以折扣。如存在小数,按四舍五入规则计算,保留整数。
折扣的计算方法(注:以下时间段均按闭区间计算):
周一至周五营业时间与折扣:晚上(17:00-20:30)8折,周一至周五中午(10:30--14:30)6折,其余时间不营业。
周末全价,营业时间:9:30-21:30
如果下单时间不在营业范围内,输出"table " + t.tableNum + " out of opening hours"
参考以下类的模板进行设计:菜品类:对应菜谱上一道菜的信息。
Dish
String name;//菜品名称
int unit_price; //单价
int getPrice(int portion)//计算菜品价格的方法,输入参数是点菜的份额(输入数据只能是1/2/3,代表小/中/大份)
菜谱类:对应菜谱,包含饭店提供的所有菜的信息。
Menu
Dish\\[\\] dishs ;//菜品数组,保存所有菜品信息
Dish searthDish(String dishName)//根据菜名在菜谱中查找菜品信息,返回Dish对象。
Dish addDish(String dishName,int unit_price)//添加一道菜品信息
点菜记录类:保存订单上的一道菜品记录
Record
int orderNum;//序号\\\\
Dish d;//菜品\\\\
int portion;//份额(1/2/3代表小/中/大份)\\\\
int getPrice()//计价,计算本条记录的价格\\\\
订单类:保存用户点的所有菜的信息。
Order
Record\\[\\] records;//保存订单上每一道的记录
int getTotalPrice()//计算订单的总价
Record addARecord(int orderNum,String dishName,int portion,int num)//添加一条菜品信息到订单中。
delARecordByOrderNum(int orderNum)//根据序号删除一条记录
findRecordByNum(int orderNum)//根据序号查找一条记录
### 输入格式:
桌号标识格式:table + 序号 +英文空格+ 日期(格式:YYYY/MM/DD)+英文空格+ 时间(24小时制格式: HH/MM/SS)
菜品记录格式:
菜名+英文空格+基础价格
如果有多条相同的菜名的记录,菜品的基础价格以最后一条记录为准。
点菜记录格式:序号+英文空格+菜名+英文空格+份额+英文空格+份数注:份额可输入(1/2/3), 1代表小份,2代表中份,3代表大份。
删除记录格式:序号 +英文空格+delete
代点菜信息包含:桌号+英文空格+序号+英文空格+菜品名称+英文空格+份额+英文空格+分数
最后一条记录以“end”结束。
### 输出格式:
按输入顺序输出每一桌的订单记录处理信息,包括:
1、桌号,格式:table+英文空格+桌号+”:”
2、按顺序输出当前这一桌每条订单记录的处理信息,
每条点菜记录输出:序号+英文空格+菜名+英文空格+价格。其中的价格等于对应记录的菜品\\*份数,序号是之前输入的订单记录的序号。如果订单中包含不能识别的菜名,则输出“\\*\\* does not exist”,\\*\\*是不能识别的菜名
如果删除记录的序号不存在,则输出“delete error”
最后按输入顺序一次输出每一桌所有菜品的总价(整数数值)格式:table+英文空格+桌号+“:”+英文空格+当前桌的总价
本次题目不考虑其他错误情况,如:桌号、菜单订单顺序颠倒、不符合格式的输入、序号重复等,在本系列的后续作业中会做要求。
输入格式:
桌号标识格式:table + 序号 +英文空格+ 日期(格式:YYYY/MM/DD)+英文空格+ 时间(24小时制格式: HH/MM/SS)
菜品记录格式:
菜名+英文空格+基础价格
如果有多条相同的菜名的记录,菜品的基础价格以最后一条记录为准。
点菜记录格式:序号+英文空格+菜名+英文空格+份额+英文空格+份数注:份额可输入(1/2/3), 1代表小份,2代表中份,3代表大份。
删除记录格式:序号 +英文空格+delete
代点菜信息包含:桌号+英文空格+序号+英文空格+菜品名称+英文空格+份额+英文空格+分数
最后一条记录以“end”结束。
输出格式:
按输入顺序输出每一桌的订单记录处理信息,包括:
1、桌号,格式:table+英文空格+桌号+“:”
2、按顺序输出当前这一桌每条订单记录的处理信息,
每条点菜记录输出:序号+英文空格+菜名+英文空格+价格。其中的价格等于对应记录的菜品\\*份数,序号是之前输入的订单记录的序号。如果订单中包含不能识别的菜名,则输出“\\*\\* does not exist”,\\*\\*是不能识别的菜名
如果删除记录的序号不存在,则输出“delete error”
最后按输入顺序一次输出每一桌所有菜品的总价(整数数值)格式:table+英文空格+桌号+“:”+英文空格+当前桌的总价
本次题目不考虑其他错误情况,如:桌号、菜单订单顺序颠倒、不符合格式的输入、序号重复等,在本系列的后续作业中会做要求。
解题步骤
这道题目我先按题目要求写了一些必要的类如Dish Order Record等,在写Menu类时想到菜单应该只有一张,所以我把菜单用单例模式来处理
菜单类的源码如下:
package MenuPricing; public class Menu private static Menu menu = null; private Dish[] dishs = ; private Menu() public static Menu getMenu() if(menu == null) menu = new Menu(); return menu; public Dish[] getDishs() return dishs; public void setDishs(Dish[] dishs) this.dishs = dishs; public Dish searthDish(String dishName) for(Dish i: dishs) if(i.getName().equals(dishName)) return i; return null; public void changeMenu(String dishName , int price ) for(int i = 0 ; i < this.dishs.length ; i++) if(dishName.equals(this.dishs[i].getName())) dishs[i] = new Dish( dishName, price); public Dish addDish(String dishName,int unit_price) Dish dish = new Dish(dishName , unit_price); Dish[] newdishs = new Dish[this.dishs.length+1]; for(int i = 0 ; i < this.dishs.length ; i++) newdishs[i] = this.dishs[i]; newdishs[this.dishs.length] = dish; this.dishs = newdishs ; return dish; public Dish addDish(String dishName,int unit_price,boolean special) Dish dish = new Dish(dishName , unit_price , true); if(this.searthDish(dishName).getName().equals(dishName)) for(int i = 0 ; i < this.dishs.length ; i++) if(this.dishs[i].getName().equals(dishName)) this.dishs[i].setUnit_price(unit_price); this.dishs[i].setSpecial(special); else Dish[] newdishs = new Dish[this.dishs.length+1]; for(int i = 0 ; i < this.dishs.length ; i++) newdishs[i] = this.dishs[i]; newdishs[this.dishs.length] = dish; this.dishs = newdishs ; return dish;
这里单例用的是懒汉式并没有通过加锁等方式确保线程安全。
最终再玩成主方法的编写
由于该题目需要根据不同的用户输入来处理数据所以要对文本进行正确处理我这里采用但是使用Spring中的split方法切割字符串接着对切割后的字符串进行处理。
OOP训练集5
7-5 日期问题面向对象设计(聚合一)
给出了类图,让我们根据类图实现相应功能
由于给出了类图,我们只需完成相应类中的方法编写以及主方法的写法即可完成解答,以下是我写的代码所生成的类图
7-6 日期问题面向对象设计(聚合二)
该题目所完成的相应功能与上一题相同,但其中的类与类简单关系不同,只需再上一题的基础上更改类的关系,修改相应的代码即可完成解答
下面是根据我写的代码生成的类图:
OOP训练集6
7-1 菜单计价程序-4
该题目是对训练集4中的第一题进行迭代升级新增了桌号、菜单订单顺序颠倒、不符合格式的输入、序号重复等错误输入情况,要求对用户的输入进行更精准的判断,新增了特色菜的功能考验了原 先代码的可拓展性。
解题步骤,根据新增的特色菜功能对Dish类进行修改,新增boolean类型属性special用于记录是否该菜品为特色菜
Dish类的类图如下:
然后根据特色菜的功能修改菜价的计算方式,这样算是完成了特色菜的功能
然后处理桌号、菜单订单顺序颠倒、不符合格式的输入、序号重复等错误,在Main类中新增一些方法处理相应错误
最终类图如下:
3.踩坑心得
在做菜单计价程序写Menu类时,要写一个方法根据传进来的菜品名称改变菜单信息,此时要将菜品名称与菜单中的菜品名称一 一比对,一开始我使用的是“ == ”判断,但运行后发现不行,要改为equals判断,原因是==是判断两个变量或实例是不是指向同一个内存空间,equals是判断两个变量或实例所指向的内存空间的值是不是相同,简单来说是==是指对内存地址进行比较 , equals()是对字符串的内容进行比较。
后来还查了一下compareTo()的原理,它获取的字符串(也可以是其他对象)的长度,然后作ASCII码的减法,可以判断返回的数值是否为零判断是否相等。
4.改进建议
对用户输入数据的处理方法不够成熟,应该改为用正则表达式去匹配,这样可以更精准的匹配到用户的操作,更准确的判断是否用户输入有误。
写代码前应该先做设计,想好程序结构再开始写。这样可以避免应程序结构的问题反复修改代码。
5.总结
通过这三次的实验掌握了基本的聚合,依赖等类间关系的使用,熟悉了powerdesingner的运用,练习了正则表达式的使用,理解了“==”,equals(),compareTo()的区别。
这三次的题目集还让我充分意识到自己的许多不足
1.写代码前应先想整个程序的结构,想清楚再写,不然结构一错基本要全部重写
2.写代码时一定要写注释,要不然昨天写的代码第二天就不知道那个方法的用处
3.不要过分的高估自己的能力,提前写完,要不然等到最后几天开始写就来不及了
PTA团体程序设计天梯赛-练习集 L3题目总结(不全)
模拟题
STL题
L3-002 特殊堆栈(两个vector)
#include<bits/stdc++.h>
using namespace std;
#define fir(i,a,n) for(int i=a;i<=n;i++)
#define mem(a,x) memset(a,x,sizeof(a));
#define pb push_back
typedef long long ll;
const int N=1e5+10;
int n;
vector<int>v,v1;//v有序
int main()
cin>>n;
while(n--)
string a;cin>>a;
if(a=="Pop")
if(v1.empty()) puts("Invalid");
else
int t=v1.back();
auto it=lower_bound(v.begin(),v.end(),t);
v.erase(it);
cout<<t<<endl;
v1.pop_back();
else if(a=="PeekMedian")
if(v1.empty()) puts("Invalid");
else cout<<v[(v.size()+1)/2-1]<<endl;
else
int t;cin>>t;
v1.pb(t);
auto it=lower_bound(v.begin(),v.end(),t);
v.insert(it,t);
return 0;
dp题
搜索题
L3-001 凑零钱(dfs)
dfs:从小到大排列,找到的第一个答案就是序列最小的答案。如果从大到小排列会TLE两个点。
也可以dp(01背包)。
#include<bits/stdc++.h>
using namespace std;
#define fir(i,a,n) for(int i=a;i<=n;i++)
#define mem(a,x) memset(a,x,sizeof(a));
#define pb push_back
typedef long long ll;
const int N=1e4+10;
int n,m,a[N],sum,fl;
vector<int>ans,anss;
void dfs(int u,int sum)
if(fl) return;
if(sum>m) return;
if(sum==m)
fl=1;
anss=ans;
return;
for(int i=u;i<=n;i++)
ans.pb(a[i]);
dfs(i+1,sum+a[i]);
ans.pop_back();
int main()
cin>>n>>m;
fir(i,1,n)
cin>>a[i];sum+=a[i];
if(sum<m)
cout<<"No Solution";return 0;
sort(a+1,a+1+n);
dfs(1,0);
if(fl)
int f=0;
for(auto x:anss)
if(f) cout<<" ";
cout<<x;f++;
else cout<<"No Solution";
return 0;
L3-004 肿瘤诊断(bfs)
三维bfs。
dfs会段错误,估计是递归次数太多了。
#include<bits/stdc++.h>
using namespace std;
#define fir(i,a,n) for(int i=a;i<=n;i++)
#define mem(a,x) memset(a,x,sizeof(a));
#define pb push_back
typedef long long ll;
const int N=1500+10;
int g[1300][130][80],v[1300][130][80];
int n,m,l,t;
int ans,temp;
int dx[6]=0,0,0,0,1,-1;
int dy[6]=0,0,1,-1,0,0;
int dz[6]=1,-1,0,0,0,0;
struct node
int x,y,z;
;
void bfs(int x,int y,int z)
queue<node>q;
q.push(x,y,z);
while(q.size())
node t=q.front();q.pop();
for(int i=0;i<6;i++)
int xx=t.x+dx[i];
int yy=t.y+dy[i];
int zz=t.z+dz[i];
if(xx>=1&&xx<=m&&yy>=1&&yy<=n&&zz>=1&&zz<=l)
if(!v[xx][yy][zz]&&g[xx][yy][zz])
v[xx][yy][zz]=1;
temp++;
q.push(xx,yy,zz);
int main()
cin>>m>>n>>l>>t;
fir(i,1,l)
fir(j,1,m)
fir(k,1,n)
cin>>g[j][k][i];
fir(i,1,l)
fir(j,1,m)
fir(k,1,n)
if(!v[j][k][i]&&g[j][k][i])
temp=1;
v[j][k][i]=1;
bfs(j,k,i);
if(temp>=t) ans+=temp;
cout<<ans;
return 0;
L3-008 喊山(bfs)
没懂“题目假设每个山头最多有两个能听到它的临近山头”的意思,直接模板bfs一下。
#include<bits/stdc++.h>
using namespace std;
#define fir(i,a,n) for(int i=a;i<=n;i++)
#define mem(a,x) memset(a,x,sizeof(a));
#define pb push_back
typedef long long ll;
const int N=1e4+10;
int n,m,k;
vector<int>g[N];
struct node
int a,ans;
;
int id,maxn;
int v[N];
int bfs(int x)
memset(v,0,sizeof(v));
queue<node>q;
q.push(x,0);
v[x]=1;
id=-1,maxn=-1;
while(q.size())
node t=q.front();q.pop();
for(auto u:g[t.a])
if(v[u]) continue;
v[u]=1;
node temp=u,t.ans+1;
if(t.ans+1>maxn)
maxn=t.ans+1;
id=u;
else if(t.ans+1==maxn&&u<id)
id=u;
q.push(temp);
return id;
int main()
cin>>n>>m>>k;
fir(i,1,m)
int a,b;cin>>a>>b;
g[a].pb(b);g[b].pb(a);
while(k--)
int kk;cin>>kk;
int ans=bfs(kk);
if(ans==-1) puts("0");
else cout<<ans<<endl;
return 0;
图论题
L3-011 直捣黄龙(dij+dfs+map)
要素过多的大杂烩属于是。
听说直接dfs也可以满分,数据有点水。
#include<bits/stdc++.h>
using namespace std;
#define fir(i,a,n) for(int i=a;i<=n;i++)
#define ll long long
#define pb push_back
const int N=200+10;
int n,m;
string start,endd;
map<string,int>mp;
map<int,string>mpp;
int idx=1;
void add(string a)
mp[a]=idx;
mpp[idx]=a;
idx++;
int p[N];//people
int g[N][N];
int ss,ee;//start end
int dist[N],st[N];
int dij()
memset(dist,0x3f,sizeof(dist));
dist[ss]=0;
for(int i=1;i<=n;i++)
int t=-1;
for(int j=1;j<=n;j++)
if(!st[j]&&(t==-1||dist[j]<dist[t]))
t=j;
st[t]=1;
for(int j=1;j<=n;j++)
dist[j]=min(dist[j],dist[t]+g[t][j]);
return dist[ee];
int minn,all,killl;
vector<int>ans,temp;
int v[N];
void dfs(int u,int kill)
if(u==ee)
all++;
if(temp.size()>ans.size())
ans=temp;killl=kill;
else if(temp.size()==ans.size()&&kill>killl)
killl=max(killl,kill);ans=temp;
return;
for(int i=1;i<=n;i++)
if(!v[i]&&dist[i]==dist[u]+g[u][i])
v[i]=1;
temp.pb(i);
dfs(i,kill+p[i]);
temp.pop_back();
v[i]=0;
int main()
cin>>n>>m>>start>>endd;
add(start);add(endd);
fir(i,1,n-1)
string a;int b;cin>>a>>b;
if(mp.find(a)==mp.end())
add(a);
int t=以上是关于PTA题目集4~6的总结的主要内容,如果未能解决你的问题,请参考以下文章