关于前三次pta的总结
前言
这三次pta难度在不断上升的同时,要求我们线上慕课+自主学习来了解更多的java中的各种方法,如:正则表达式 List Map等。与此同时要求我们展开尝试并熟练类的构造,类的引用,链表的基本运用,封装性,比较接口,比较方法,toString的使用。每一次pta作业都会先以几个小题来引入本次pta所要侧重的知识点,同时也是这次我们需要学习掌握的用以解决最后一题的方法,前几道小题是解决最后一题的钥匙,理解并掌握前几个小题才能去尝试完成第三题。经过最后一题的层层迭代,最后一题只会越来越难,这是一场艰难的挑战,我们要坚定信念,砥砺前行,才能夺得最后的成功。
面向对象的设计原则:
- 单一职责原则(There should never be more than one reason for a class to change.)
- 里氏替换原则( Liskov Substitution Principle, LSP )
- 依赖倒置原则( Dependence Inversion Principle,DIP )
- 接口隔离原则(Interface Segregation Principle)
- 迪米特法则(Law of Demeter,LoD)
- 开闭原则(Open Closed Principle)
设计与分析
第一次pta
第一次pta最后一题,比较简单,输入十分有规律,并没有太多坑,按照规律哪怕直接使用数组加链表也能写出来,更何况老师还给了设计建议使用三个class来进行分解。
设计建议:
以下是针对以上题目要求的设计建议,其中的属性、方法为最小集,实现代码中可根据情况添加所需的内容:
题目类(用于封装单个题目的信息):
属性:题目编号、题目内容、标准答案-standardAnswer
方法:数据读写set\get方法、
判题方法(答案-answer):判断答案-answer是否符合标准答案-standardAnswer
试卷类(用于封装整套题目的信息)
属性:题目列表(题目类的对象集合)、题目数量
方法:判题方法(题号-num、答案-answer):判断答案-answer是否符合对应题号的题目标准答案-standardAnswer
保存题目(题号-num、题目-question):将题目保存到题目列表中,保存位置与num要能对应
答卷类(用于封装答题信息)
属性:试卷(试卷类的对象)、答案列表(保存每一题的答案)、判题列表(保存每一题的判题结果true/false)
方法:判题方法(题号-num):判断答案列表中第num题的结果是否符合试卷中对应题号的题目标准答案
输出方法(题号-num):按照题目的格式要求,输出题号为num的题目的内容和答题结果。
保存一个答案(题号-num,答案-answer):保存题号为num的题目的答题结果answer。
设计实现答题程序,模拟一个小型的测试,要求输入题目信息和答题信息,根据输入题目信息中的标准答案判断答题的结果。
输入格式:
程序输入信息分三部分:
1、题目数量
格式:整数数值,若超过1位最高位不能为0,
样例:34
2、题目内容
一行为一道题,可以输入多行数据。
格式:"#N:"+题号+" "+"#Q:"+题目内容+" "#A:"+标准答案
格式约束:题目的输入顺序与题号不相关,不一定按题号顺序从小到大输入。
样例:#N:1 #Q:1+1= #A:2
#N:2 #Q:2+2= #A:4
3、答题信息
答题信息按行输入,每一行为一组答案,每组答案包含第2部分所有题目的解题答案,答案的顺序号与题目题号相对应。
格式:"#A:"+答案内容
格式约束:答案数量与第2部分题目的数量相同,答案之间以英文空格分隔。
样例:#A:2 #A:78
2是题号为1的题目的答案
78是题号为2的题目的答案
答题信息以一行"end"标记结束,"end"之后的信息忽略。
输出格式:
1、题目数量
格式:整数数值,若超过1位最高位不能为0,
样例:34
2、答题信息
一行为一道题的答题信息,根据题目的数量输出多行数据。
格式:题目内容+" ~"+答案
样例:1+1=~2
2+2= ~4
3、判题信息
判题信息为一行数据,一条答题记录每个答案的判断结果,答案的先后顺序与题目题号相对应。
格式:判题结果+" "+判题结果
这段代码是搬运同学的代码,我的代码并没有使用class类,违背了单一职责原则 等各种原则,是一个Main主函数走天下,正能作为反面教材,因此采用同学的代码进行讲解
import java.util.Scanner;
import java.util.ArrayList;
import java.util.List;
class Problem {
private int number;
private String content;
private String standardAnswer;
public Problem(int number, String content, String standardAnswer) {
super();
this.number = number;
this.content = content;
this.standardAnswer = standardAnswer;
}
public Problem() {
super();
}
public int getNumber() {
return number;
}
public void setNumber(int number) {
this.number = number;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public String getStandardAnswer() {
return standardAnswer;
}
public void setStandardAnswer(String standardAnswer) {
this.standardAnswer = standardAnswer;
}
public boolean judgeAnswer(String answer) {
return this.standardAnswer.equals(answer);
}
public String getproblem() {
return content + "~" + standardAnswer;
}
}
class Testpaper {
List problemlist ;
public Testpaper() {
super();
this.problemlist = new ArrayList<>();
}
public void addproblem(int number, String content, String standardAnswer) {
Problem problem = new Problem(number,content,standardAnswer);
problemlist.add(problem);
}
public void removeproblem(int number) {
int i=0;
for(i=0;i<99;i++)
{
if(this.problemlist.get(i).getNumber()==number)
{
problemlist.remove(i);
break;
}
}
}
public boolean judgeAnswer(int number,String answer) {
for(int i = 0;i<problemlist.size();i++)
{
if(problemlist.get(i).getNumber() == (number+1))
{
Problem problem = problemlist.get(i);
return problem.judgeAnswer(answer);
}
}
return false;
}
public String getproblem(int number) {
Problem problem = problemlist.get(number-1);
return problem.getproblem();
}
}
class Answerpaper {
List answerlist;
List answernumberlist;
List numberlist;
private Testpaper testpaper;
public Answerpaper(Testpaper testpaper) {
super();
this.testpaper = testpaper;
this.answerlist=new ArrayList<>();
this.answernumberlist = new ArrayList<>();
this.numberlist = new ArrayList<>();
}
public void addAnswer(String answer) {
answerlist.add(answer);
}
public void addAnswernumber(int number) {
answernumberlist.add(number);
}
public void addnumber(int number) {
numberlist.add(number);
}
public boolean judgeAnswer(int number) {
String answer = answerlist.get(number);
return testpaper.judgeAnswer(number,answer);
}
public String getanswer(int number) {
return answerlist.get(number-1);
}
}
public class Main {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
Testpaper testpaper = new Testpaper();
Answerpaper answerpaper = new Answerpaper(testpaper);
int num = input.nextInt();
while (input.hasNextLine()) {
String line = input.nextLine();
if (line.equals("end")) {
break;
}
if(line.startsWith("#N:")) {
String parts[]=line.split("#Q:|#A:|#N:");
testpaper.addproblem(Integer.parseInt(parts[1].trim()),parts[2].trim(),parts[3].trim());
}
else if(line.startsWith("#A:")) {
String parts[]=line.split("#A:");
for(int i=0;i<parts.length-1;i++)
{
answerpaper.addAnswer(parts[i+1].trim());
}
}
}
for(int i=0;i<testpaper.problemlist.size();i++)
{
for(int j = 0;j<testpaper.problemlist.size();j++)
{
if(testpaper.problemlist.get(j).getNumber() == i+1) {
System.out.println(testpaper.problemlist.get(j).getContent()+"~"+answerpaper.answerlist.get(i));
}
}
}
for(int i=0;i<testpaper.problemlist.size();i++)
{
for(int j = 0;j<testpaper.problemlist.size();j++)
{
if(testpaper.problemlist.get(j).getNumber() == i+1) {
System.out.print(answerpaper.judgeAnswer(i));
if(i!=testpaper.problemlist.size()-1)
{
System.out.print(" ");
}
}
}
}
}
}
代码分析
将题目信息保存在Problem中,在使用List链表将Problem串联在一起,一起放入TestPaper中,再由AnswerPaper包含TestPaper,层层嵌套。
Testpaper testpaper = new Testpaper();//生成TestPaper类。
Answerpaper answerpaper = new Answerpaper(testpaper);//生成AnswerPaper类 将TestPaper包含与AnswerPaper中。
List problemlist ;//这是TestPaper中的元素,利用链表将Problem串联起来。
split 这是我解决这道题的关键,通过分割来得到问题 答案 的各个需要的主体。
startWith 同样是一个关键,用于判断输入的这一行是问题还是答案
第二次pta
第二次pta最后一题在第一次最后一题的基础上进行迭代,增添了试卷这一新输入,并且要求计算分数,如:分数总和是否满100,不同试卷对同一题的分数设定不同,答案个数与题目数不对等,不同试卷题目数不同等各种情况。相较于第一题,第二题的难度提升非常巨大,初次看到这题,我直接看昏了,读了数次题目才了解大概要求。虽然同样给了设计建议,但依旧十分困难。
设计建议:
参考答题判题程序-1,建议增加答题类,类的内容以及类之间的关联自行设计。
设计实现答题程序,模拟一个小型的测试,以下粗体字显示的是在答题判题程序-1基础上增补或者修改的内容。
要求输入题目信息、试卷信息和答题信息,根据输入题目信息中的标准答案判断答题的结果。
输入格式:
程序输入信息分三种,三种信息可能会打乱顺序混合输入:
1、题目信息
一行为一道题,可输入多行数据(多道题)。
格式:"#N:"+题目编号+" "+"#Q:"+题目内容+" "#A:"+标准答案
格式约束:
1、题目的输入顺序与题号不相关,不一定按题号顺序从小到大输入。
2、允许题目编号有缺失,例如:所有输入的题号为1、2、5,缺少其中的3号题。此种情况视为正常。
样例:#N:1 #Q:1+1= #A:2
#N:2 #Q:2+2= #A:4
2、试卷信息
一行为一张试卷,可输入多行数据(多张卷)。
格式:"#T:"+试卷号+" "+题目编号+"-"+题目分值
题目编号应与题目信息中的编号对应。
一行信息中可有多项题目编号与分值。
样例:#T:1 3-5 4-8 5-2
3、答卷信息
答卷信息按行输入,每一行为一张答卷的答案,每组答案包含某个试卷信息中的题目的解题答案,答案的顺序与试卷信息中的题目顺序相对应。
格式:"#S:"+试卷号+" "+"#A:"+答案内容
格式约束:答案数量可以不等于试卷信息中题目的数量,没有答案的题目计0分,多余的答案直接忽略,答案之间以英文空格分隔。
样例:#S:1 #A:5 #A:22
1是试卷号
5是1号试卷的顺序第1题的题目答案
22是1号试卷的顺序第2题的题目答案
答题信息以一行"end"标记结束,"end"之后的信息忽略。
输出格式:
1、试卷总分警示
该部分仅当一张试卷的总分分值不等于100分时作提示之用,试卷依然属于正常试卷,可用于后面的答题。如果总分等于100分,该部分忽略,不输出。
格式:"alert: full score of test paper"+试卷号+" is not 100 points"
样例:alert: full score of test paper2 is not 100 points
2、答卷信息
一行为一道题的答题信息,根据试卷的题目的数量输出多行数据。
格式:题目内容+""+答案++""+判题结果(true/false)
约束:如果输入的答案信息少于试卷的题目数量,答案的题目要输"answer is null"
样例:3+2=5true
4+6=~22~false.
answer is null
3、判分信息
判分信息为一行数据,是一条答题记录所对应试卷的每道小题的计分以及总分,计分输出的先后顺序与题目题号相对应。
格式:题目得分+" "+....+题目得分+"~"+总分
格式约束:
1、没有输入答案的题目计0分
2、判题信息的顺序与输入答题信息中的顺序相同
样例:5 8 0~13
根据输入的答卷的数量以上2、3项答卷信息与判分信息将重复输出。
4、提示错误的试卷号
如果答案信息中试卷的编号找不到,则输出”the test paper number does not exist”,参见样例9。
import java.util.Arrays;
public class AnswerPaper {
protected TestPaper paper;
protected String[] answers ;
protected int[] answerNum = new int [0];
protected boolean[] marks;
public AnswerPaper() {
// TODO Auto-generated constructor stub
}
public AnswerPaper(TestPaper paper) {
super();
this.paper = paper;
}
public void InputAnswer(String[] answers) {
this.answers = answers;
}
//输入题号 答案
public void inputAnswer(int num,String answer) {
answers = Arrays.copyOf(answers,answers.length+1);
answers[answers.length] = answer;
answerNum = Arrays.copyOf(answerNum, answerNum.length+1);
answerNum[answerNum.length] = num;
}
}
import java.util.regex.Pattern;
import java.util.Arrays;
import java.util.regex.Matcher;
public class InputMatching {
//匹配题目
//返还题号
public static String questionNumMatching(String question) {
String[] result = question.split(" ");
String[] part = result[0].split(":");
return part[1];
}
//返还题目
public static String questionMatching (String question) {
String[] result = question.split(" ");
String[] part = result[1].split(":");
return part[1];
}
//返还标答
public static String standardAnswerMatching (String question) {
String[] result = question.split(" ");
String[] part = result[2].split(":");
return part[1];
}
//返还答案号
public static String answerNumMatching(String Answer) {
String[] result = Answer.split(" ");
String[] part = result[0].split(";
return part[1];
}
//返还答案字符组
public static String[] answerMatching(String Answer) {
String ces = "?<=(#A:).+?=( )";
Pattern pattern = Pattern.compile(ces);
Matcher matcher = pattern.matcher(Answer);
String[] result = new String [1];
int i = 0;
while(matcher.find()) {
result[i] = matcher.group();
i++;
result = Arrays.copyOf(result,result.length+1);
}
return result;
}
}
import java.util.Arrays;
public class ParaseInput {
//匹配试卷的题目
//匹配题号
public static String[] MatchingQuestionNum(String line) {
String[] resu = new String [0];
String[] result = line.split(" ");
for(int k=1;k<result.length;k++) {
String[] part = result[k].split("-");
resu = Arrays.copyOf(resu,resu.length+1);
resu[k-1] = part[0];
}
return resu;
}
//匹配分数
public static String[] MatchingQuestionGrace(String line) {
String[] resu = new String [0];
String[] result = line.split(" ");
for(int k=1;k<result.length;k++) {
String[] part = result[k].split("-");
resu = Arrays.copyOf(resu,resu.length+1);
resu[k-1] = part[1];
}
return resu;
}
}
public class Question {
protected int num;
protected String cotent;
protected String standardAnswer;
public Question() {
// TODO Auto-generated constructor stub
}
public Question(int num, String cotent, String standardAnswer) {
this.num = num;
this.cotent = cotent;
this.standardAnswer = standardAnswer;
}
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
public String getCotent() {
return cotent;
}
public void setCotent(String cotent) {
this.cotent = cotent;
}
public String getStandardAnswer() {
return standardAnswer;
}
public void setStandardAnswer(String standardAnswer) {
this.standardAnswer = standardAnswer;
}
}
import java.util.Arrays;
public class TestPaper {
protected int number;//试卷号
protected int questionNum = 0;//题目数量
protected Question[] questions = new Question[0];
protected int[] questionsGrace = new int[0];
public TestPaper() {
// TODO Auto-generated constructor stub
}
public TestPaper(int number) {
this.number = number;
}
//输入题号 题目
public void inputQuestion(int num,Question question) {
this.questions = Arrays.copyOf(questions,questions.length+1);
this.questions[questions.length] = question;
this.questions[questions.length].num = num;
questionNum++;
}
//输入题目分数
public void inputQuestionGrace(int grace) {
this.questionsGrace = Arrays.copyOf(questionsGrace, questionsGrace.length+1);
this.questionsGrace[questionsGrace.length] = grace;
}
public void InputGrace() {
int sum = 0;
for(int i=0;i<this.questionsGrace.length;i++) {
sum+=questionsGrace[i];
}
if(sum!=100) {
System.out.println("alert: full score of test paper"+number+" is not 100 points");
}
}
}
import java.util.Arrays;
import java.util.Scanner;
public class Main {
public static void main(String [] args) {
Scanner input = new Scanner(System.in);
String line = input.nextLine();
int questionNum=0,paperNum=0,answerNum=0;//题目数量 试卷数量 答卷数量
Question[] question = new Question[0];
TestPaper[] paper = new TestPaper[0];
AnswerPaper[] answers = new AnswerPaper[0];
// Question question = new Question();
while(!(line.equals("end"))) {
//如果输入是题目
if(line.startsWith("#N:")) {
question = Arrays.copyOf(question,question.length+1);
question[questionNum] = new Question(Integer.parseInt(InputMatching.questionNumMatching(line)),InputMatching.questionMatching(line),InputMatching.standardAnswerMatching(line));
questionNum++;
}
//如果输入试卷
if(line.startsWith("#T:")) {
paper = Arrays.copyOf(paper, paper.length+1);
paper[paperNum] = new TestPaper(paperNum+1);
for(int j=0;j<ParaseInput.MatchingQuestionNum(line).length;j++) {
for(int i=0;i<questionNum;i++) {
if(question[i].num==Integer.parseInt(ParaseInput.MatchingQuestionNum(line)[j])) {
paper[paperNum].inputQuestion(question[i].num, question[i]);
paper[paperNum].inputQuestionGrace(Integer.parseInt(ParaseInput.MatchingQuestionGrace(line)[j]));
}
}
}
}
//如果输入答案
if(line.startsWith("#S:")) {
answers = Arrays.copyOf(answers, answers.length+1);
for(int i=0;i<paperNum;i++) {
if(paper[i].number==(Integer.parseInt(InputMatching.answerNumMatching(line)))) {
answers[answerNum] = new AnswerPaper(paper[i]);
answers[answerNum].InputAnswer(InputMatching.answerMatching(line));
}
}
}
line = input.nextLine();
}
//输出分数是否100
for(int i=0;i<paperNum;i++) {
paper[i].InputGrace();
}
//输出题目与答案
for(int i=0;i<answerNum;i++) {
for(int j=0;j<paper[i].questionNum;j++) {
if(j>answers[i].answers.length) {
System.out.println("answer is null");
continue;
}
System.out.println(answers[answerNum].paper.questions[j].cotent+"~"+answers[answerNum].answers[j]+"~"+answers[answerNum].paper.questions[j].standardAnswer.equals(answers[answerNum].answers[j]));
}
for(int k=0,grace=0;k<paper[i].questionNum;k++) {
if(k>answers[i].answers.length) {
System.out.printf("0");
if(k!=paper[i].questionNum-1) {
System.out.printf(" ");
}
else {
System.out.printf("~");
}
}
if(answers[answerNum].paper.questions[k].standardAnswer.equals(answers[answerNum].answers[k])) {
System.out.printf("%d", answers[answerNum].paper.questionsGrace[k]);
grace+=answers[answerNum].paper.questionsGrace[k];
if(k!=paper[i].questionNum-1) {
System.out.printf(" ");
}
else {
System.out.printf("~");
}
}
else {
System.out.printf("0");
if(k!=paper[i].questionNum-1) {
System.out.printf(" ");
}
else {
System.out.printf("~");
}
}
System.out.println(grace);
}
}
input.close();
}
}
代码分析
这段代码有缺陷,并不能完好的解决这一难题
这段代码是在第一次pta最后一题的基础上进行迭代,同样的是Question类存储题目信息,再有TestPaper类存储试卷信息并由存储的试卷信息来匹配题目,在使用Question[]数组来存储时均需要的Question题目信息,然后是AnswerPaper类通过试卷号TestPaperNumber来匹配试卷,再将试卷TestPaper保存到AnswerPaper中去。
关于对第一次的迭代:
新增InputMatching类 用于进行分割#N:题目信息和#S:答案信息。依旧是使用Split方法来进行分割取得各个需求的数据
新增ParaseInput类 用于进行分割#T:试卷信息
关于这次的代码:
各个信息之间的匹配很重要本来想要使用Map来进行编写,但Map这一方法使用的并不熟练,遂只能按照第一次pta中一样使用equals方法来进行匹配
相较于第一次pta最后一题,第二次pta最后一题的输出不在规律,为此我是用while(!(line = input.nextLine().equals("end")))这一循环,再搭配#N:||#S:||#T: 来分别处理,分开后按照不同结构,不同切割法
第三次pta
第三次Pta最后一题是在第二次Pta最后一题的基础上在进行升级,增加了学生信息这一新输入,并且还有#D:删除某一题目信息,第二次pta最后一题对于我来说就已经非常困难,这一题更是雪上加霜,,并且各种错误输入,一丝规律都难找,我仿佛就像遇到危险的鸵鸟,只能把他伸进沙子中,假装没看到。
设计实现答题程序,模拟一个小型的测试,以下粗体字显示的是在答题判题程序-2基础上增补或者修改的内容,要求输入题目信息、试卷信息、答题信息、学生信息、删除题目信息,根据输入题目信息中的标准答案判断答题的结果。
输入格式:
程序输入信息分五种,信息可能会打乱顺序混合输入。
1、题目信息
题目信息为独行输入,一行为一道题,多道题可分多行输入。
格式:"#N:"+题目编号+" "+"#Q:"+题目内容+" "#A:"+标准答案
格式约束:
1、题目的输入顺序与题号不相关,不一定按题号顺序从小到大输入。
2、允许题目编号有缺失,例如:所有输入的题号为1、2、5,缺少其中的3号题。此种情况视为正常。
样例:#N:1 #Q:1+1= #A:2
#N:2 #Q:2+2= #A:4
2、试卷信息
试卷信息为独行输入,一行为一张试卷,多张卷可分多行输入数据。
格式:"#T:"+试卷号+" "+题目编号+"-"+题目分值+" "+题目编号+"-"+题目分值+...
格式约束:
题目编号应与题目信息中的编号对应。
一行信息中可有多项题目编号与分值。
样例:#T:1 3-5 4-8 5-2
3、学生信息
学生信息只输入一行,一行中包括所有学生的信息,每个学生的信息包括学号和姓名,格式如下。
格式:"#X:"+学号+" "+姓名+"-"+学号+" "+姓名....+"-"+学号+" "+姓名
格式约束:
答案数量可以不等于试卷信息中题目的数量,没有答案的题目计0分,多余的答案直接忽略,答案之间以英文空格分隔。
样例:
#S:1 #A:5 #A:22
1是试卷号
5是1号试卷的顺序第1题的题目答案
4、答卷信息
答卷信息按行输入,每一行为一张答卷的答案,每组答案包含某个试卷信息中的题目的解题答案,答案的顺序号与试 卷信息中的题目顺序相对应。答卷中:
格式:"#S:"+试卷号+" "+学号+" "+"#A:"+试卷题目的顺序号+"-"+答案内容+...
格式约束:
答案数量可以不等于试卷信息中题目的数量,没有答案的题目计0分,多余的答案直接忽略,答案之间以英文空格分隔。
答案内容可以为空,即””。
答案内容中如果首尾有多余的空格,应去除后再进行判断。
样例:
#T:1 1-5 3-2 2-5 6-9 4-10 7-3
#S:1 20201103 #A:2-5 #A:6-4
1是试卷号
20201103是学号
2-5中的2是试卷中顺序号,5是试卷第2题的答案,即T中3-2的答案
6-4中的6是试卷中顺序号,4是试卷第6题的答案,即T中7-3的答案
注意:不要混淆顺序号与题号
5、删除题目信息
删除题目信息为独行输入,每一行为一条删除信息,多条删除信息可分多行输入。该信息用于删除一道题目信息,题目被删除之后,引用该题目的试卷依然有效,但被删除的题目将以0分计,同时在输出答案时,题目内容与答案改为一条失效提示,例如:”the question 2 invalid~0”
格式:"#D:N-"+题目号
格式约束:
题目号与第一项”题目信息”中的题号相对应,不是试卷中的题目顺序号。
本题暂不考虑删除的题号不存在的情况。
样例:
N:1 #Q:1+1= #A:2
N:2 #Q:2+2= #A:4
T:1 1-5 2-8
X:20201103 Tom-20201104 Jack
S:1 20201103 #A:1-5 #A:2-4
D:N-2
end
输出
alert: full score of test paper1 is not 100 points
1+1=5false
the question 2 invalid~0
20201103 Tom: 0 0~0
答题信息以一行"end"标记结束,"end"之后的信息忽略。
输出格式:
1、试卷总分警示
该部分仅当一张试卷的总分分值不等于100分时作提示之用,试卷依然属于正常试卷,可用于后面的答题。如果总分等于100 分,该部分忽略,不输出。
格式:"alert: full score of test paper"+试卷号+" is not 100 points"
样例:alert: full score of test paper2 is not 100 points
2、答卷信息
一行为一道题的答题信息,根据试卷的题目的数量输出多行数据。
格式:题目内容+""+答案++""+判题结果(true/false)
约束:如果输入的答案信息少于试卷的题目数量,每一个缺失答案的题目都要输出"answer is null" 。
样例:
3+2=5true
4+6=22false.
answer is null
3、判分信息
判分信息为一行数据,是一条答题记录所对应试卷的每道小题的计分以及总分,计分输出的先后顺序与题目题号相对应。
格式:**学号+" "+姓名+": "**+题目得分+" "+....+题目得分+"~"+总分
格式约束:
1、没有输入答案的题目、被删除的题目、答案错误的题目计0分
2、判题信息的顺序与输入答题信息中的顺序相同
样例:20201103 Tom: 0 0~0
根据输入的答卷的数量以上2、3项答卷信息与判分信息将重复输出。
4、被删除的题目提示信息
当某题目被试卷引用,同时被删除时,答案中输出提示信息。样例见第5种输入信息“删除题目信息”。
5、题目引用错误提示信息
试卷错误地引用了一道不存在题号的试题,在输出学生答案时,提示”non-existent question~”加答案。例如:
输入:
N:1 #Q:1+1= #A:2
T:1 3-8
X:20201103 Tom-20201104 Jack-20201105 Www
S:1 20201103 #A:1-4
end
输出:
alert: full score of test paper1 is not 100 points
non-existent question~0
20201103 Tom: 0~0
如果答案输出时,一道题目同时出现答案不存在、引用错误题号、题目被删除,只提示一种信息,答案不存在的优先级最高,例如:
输入:
N:1 #Q:1+1= #A:2
T:1 3-8
X:20201103 Tom-20201104 Jack-20201105 Www
S:1 20201103
end
输出:
alert: full score of test paper1 is not 100 points
answer is null
20201103 Tom: 0~0
6、格式错误提示信息
输入信息只要不符合格式要求,均输出”wrong format:”+信息内容。
例如:wrong format:2 #Q:2+2= #4
7、试卷号引用错误提示输出
如果答卷信息中试卷的编号找不到,则输出”the test paper number does not exist”,答卷中的答案不用输出,参见样例8。
8、学号引用错误提示信息
如果答卷中的学号信息不在学生列表中,答案照常输出,判分时提示错误。参见样例9。
本题暂不考虑出现多张答卷的信息的情况。
输入样例1:
简单输入,不含删除题目信息。例如:
N:1 #Q:1+1= #A:2
T:1 1-5
X:20201103 Tom
S:1 20201103 #A:1-5
end
输出样例1:
在这里给出相应的输出。例如:
alert: full score of test paper1 is not 100 points
1+1=5false
20201103 Tom: 0~0
输入样例2:
简单输入,答卷中含多余题目信息(忽略不计)。例如:
N:1 #Q:1+1= #A:2
T:1 1-5
X:20201103 Tom
S:1 20201103 #A:1-2 #A:2-3
end
输出样例3
简单测试,含删除题目信息。例如:
alert: full score of test paper1 is not 100 points
1+1=2true
20201103 Tom: 5~5
输入样例3:
简单测试,含删除题目信息。例如:
N:1 #Q:1+1= #A:2
N:2 #Q:2+2= #A:4
T:1 1-5 2-8
X:20201103 Tom-20201104 Jack-20201105 Www
S:1 20201103 #A:1-5 #A:2-4
D:N-2
end
输出样例3:
在这里给出相应的输出,第二题由于被删除,输出题目失效提示。例如:
alert: full score of test paper1 is not 100 points
1+1=5false
the question 2 invalid~0
20201103 Tom: 0 0~0
输入样例4:
简单测试,含试卷无效题目的引用信息以及删除题目信息(由于题目本身无效,忽略)。例如:
N:1 #Q:1+1= #A:2
N:2 #Q:2+2= #A:4
T:1 1-5 3-8
X:20201103 Tom-20201104 Jack-20201105 Www
S:1 20201103 #A:1-5 #A:2-4
D:N-2
end
输出样例4:
输出不存在的题目提示信息。例如:
alert: full score of test paper1 is not 100 points
1+1=5false
non-existent question~0
20201103 Tom: 0 0~0
输入样例5:
综合测试,含错误格式输入、有效删除以及无效题目引用信息。例如:
N:1 +1= #A:2
N:2 #Q:2+2= #A:4
T:1 1-5 2-8
X:20201103 Tom-20201104 Jack-20201105 Www
S:1 20201103 #A:1-5 #A:2-4
D:N-2
end
输出样例5:
在这里给出相应的输出。例如:
wrong format:#N:1 +1= #A:2
alert: full score of test paper1 is not 100 points
non-existent question~0
the question 2 invalid~0
20201103 Tom: 0 0~0
输入样例6:
综合测试,含错误格式输入、有效删除、无效题目引用信息以及答案没有输入的情况。例如:
N:1 +1= #A:2
N:2 #Q:2+2= #A:4
T:1 1-5 2-8
X:20201103 Tom-20201104 Jack-20201105 Www
S:1 20201103 #A:1-5
D:N-2
end
输出样例6:
答案没有输入的优先级最高。例如:
wrong format:#N:1 +1= #A:2
alert: full score of test paper1 is not 100 points
non-existent question~0
answer is null
20201103 Tom: 0 0~0
输入样例7:
综合测试,正常输入,含删除信息。例如:
N:2 #Q:2+2= #A:4
N:1 #Q:1+1= #A:2
T:1 1-5 2-8
X:20201103 Tom-20201104 Jack-20201105 Www
S:1 20201103 #A:2-4 #A:1-5
D:N-2
end
输出样例7:
例如:
alert: full score of test paper1 is not 100 points
1+1=5false
the question 2 invalid~0
20201103 Tom: 0 0~0
输入样例8:
综合测试,无效的试卷引用。例如:
N:1 #Q:1+1= #A:2
T:1 1-5
X:20201103 Tom
S:2 20201103 #A:1-5 #A:2-4
end
输出样例8:
例如:
alert: full score of test paper1 is not 100 points
The test paper number does not exist
输入样例9:
无效的学号引用。例如:
N:1 #Q:1+1= #A:2
T:1 1-5
X:20201106 Tom
S:1 20201103 #A:1-5 #A:2-4
end
输出样例9:
答案照常输出,判分时提示错误。例如:
alert: full score of test paper1 is not 100 points
1+1=5false
20201103 not found
输入样例10:
信息可打乱顺序输入:序号不是按大小排列,各类信息交错输入。但本题不考虑引用的题目在被引用的信息之后出现的情况(如试卷引用的所有题目应该在试卷信息之前输入),所有引用的数据应该在被引用的信息之前给出。例如:
N:3 #Q:中国第一颗原子弹的爆炸时间 #A:1964.10.16
N:1 #Q:1+1= #A:2
X:20201103 Tom-20201104 Jack-20201105 Www
T:1 1-5 3-8
N:2 #Q:2+2= #A:4
S:1 20201103 #A:1-5 #A:2-4
end
输出样例10:
答案按试卷中的题目顺序输出。例如:
alert: full score of test paper1 is not 100 points
1+1=5false
中国第一颗原子弹的爆炸时间4false
20201103 Tom: 0 0~0
我的代码
import java.util.Arrays;
import java.util.Scanner;
import java.util.regex.Pattern;
import java.util.regex.Matcher;
class Question {
protected int num;
protected String cotent;
protected String standardAnswer;
public Question() {
// TODO Auto-generated constructor stub
}
public Question(int num, String cotent, String standardAnswer) {
this.num = num;
this.cotent = cotent;
this.standardAnswer = standardAnswer;
}
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
public String getCotent() {
return cotent;
}
public void setCotent(String cotent) {
this.cotent = cotent;
}
public String getStandardAnswer() {
return standardAnswer;
}
public void setStandardAnswer(String standardAnswer) {
this.standardAnswer = standardAnswer;
}
//判断答案与标准答案是否相同
public boolean matchingStandardAnswers(String answer) {
if(standardAnswer.equals(answer)) {
return true;
}
else {
return false;
}
}
}
class TestPaper {
protected int number;//试卷号
protected int questionNum = 0;//题目数量
protected Question[] questions = new Question[0];
protected int[] questionsGrace = new int[0];
public TestPaper() {
// TODO Auto-generated constructor stub
}
public TestPaper(int number) {
this.number = number;
}
//输入题号 题目
public void inputQuestion(int num,Question question) {
this.questions = Arrays.copyOf(questions,questions.length+1);
this.questions[questions.length] = question;
this.questions[questions.length].num = num;
questionNum++;
}
//输入题目分数
public void inputQuestionGrace(int grace) {
this.questionsGrace = Arrays.copyOf(questionsGrace, questionsGrace.length+1);
this.questionsGrace[questionsGrace.length] = grace;
}
//打印题目~标答
public void printQuestions() {
for(int i=0;i<questions.length;i++) {
System.out.println(questions[i].cotent+"~"+questions[i].standardAnswer);
}
}
//输入题号 答案 判断答案是否正确
public boolean markQuestion(int num,String answer) {
for(int i=0;i<questions.length;i++) {
if(num==questions[i].num) {
if(questions[i].standardAnswer.equals(answer)) {
return true;
}
}
else {
return false;
}
}
return false;
}
//判断分数
public void InputGrace() {
int sum = 0;
for(int i=0;i<this.questionsGrace.length;i++) {
sum+=questionsGrace[i];
}
if(sum!=100) {
System.out.println("alert: full score of test paper"+number+" is not 100 points");
}
}
}
class AnswerPaper {
protected TestPaper paper;
protected String[] answers ;
protected int[] answerNum = new int [0];
protected boolean[] marks;
public AnswerPaper() {
// TODO Auto-generated constructor stub
}
public AnswerPaper(TestPaper paper) {
super();
this.paper = paper;
}
public void InputAnswer(String[] answers) {
this.answers = answers;
}
//输入题号 答案
public void inputAnswer(int num,String answer) {
answers = Arrays.copyOf(answers,answers.length+1);
answers[answers.length] = answer;
answerNum = Arrays.copyOf(answerNum, answerNum.length+1);
answerNum[answerNum.length] = num;
}
//输入题号 打印题目~答案~
public void printQ_A(int num) {
for(int i=0;i<paper.questionNum;i++) {
if(paper.questions[i].num==num) {
System.out.printf("%s~",paper.questions[i].cotent);
for(int j=0;j<answerNum.length;j++) {
if(answerNum[j]==num) {
System.out.printf("%s~",answers[j]);
}
}
}
}
}
//输入题号 判断答案是否正确
public boolean getJudge(int num) {
for(int i=0;i<paper.questions.length;i++) {
if(paper.questions[i].num==num) {
for(int j=0;j<answerNum.length;j++) {
if(answerNum[j]==num) {
if(paper.questions[i].standardAnswer.equals(answers[j])) {
return true;
}
else {
return false;
}
}
}
}
}
return false;
}
}
class ParaseInput {
//匹配试卷的题目
//匹配题号
public static String[] MatchingQuestionNum(String line) {
String[] resu = new String [0];
String[] result = line.split(" ");
for(int k=1;k<result.length;k++) {
String[] part = result[k].split("-");
resu = Arrays.copyOf(resu,resu.length+1);
resu[k-1] = part[0];
}
return resu;
}
//匹配分数
public static String[] MatchingQuestionGrace(String line) {
String[] resu = new String [0];
String[] result = line.split(" ");
for(int k=1;k<result.length;k++) {
String[] part = result[k].split("-");
resu = Arrays.copyOf(resu,resu.length+1);
resu[k-1] = part[1];
}
return resu;
}
}
class InputMatching {
//匹配题目
//返还题号
public static String questionNumMatching(String question) {
String[] result = question.split(" ");
String[] part = result[0].split(":");
return part[1];
}
//返还题目
public static String questionMatching (String question) {
String[] result = question.split(" ");
String[] part = result[1].split(":");
return part[1];
}
//返还标答
public static String standardAnswerMatching (String question) {
String[] result = question.split(" ");
String[] part = result[2].split(":");
return part[1];
}
//返还题号 题目 标答
public static String questionInput(String question) {
return questionNumMatching(question)+" "+questionMatching(question)+" "+standardAnswerMatching(question);
}
//返还答案号
public static String answerNumMatching(String Answer) {
String[] result = Answer.split(" ");
String[] part = result[0].split(":");
return part[1];
}
//返还答案字符组
public static String[] answerMatching(String Answer) {
String ces = "?<=(#A:).+?=( )";
Pattern pattern = Pattern.compile(ces);
Matcher matcher = pattern.matcher(Answer);
String[] result = new String [1];
int i = 0;
while(matcher.find()) {
result[i] = matcher.group();
i++;
result = Arrays.copyOf(result,result.length+1);
}
return result;
}
}
public class Main {
public static void main(String [] args) {
Scanner input = new Scanner(System.in);
String line = input.nextLine();
int questionNum=0,paperNum=0,answerNum=0;//题目数量 试卷数量 答卷数量
Question[] question = new Question[0];
TestPaper[] paper = new TestPaper[0];
AnswerPaper[] answers = new AnswerPaper[0];
// Question question = new Question();
while(!(line.equals("end"))) {
//如果输入是题目
if(line.startsWith("#N:")) {
question = Arrays.copyOf(question,question.length+1);
question[questionNum] = new Question(Integer.parseInt(InputMatching.questionNumMatching(line)),InputMatching.questionMatching(line),InputMatching.standardAnswerMatching(line));
questionNum++;
}
//如果输入试卷
if(line.startsWith("#T:")) {
paper = Arrays.copyOf(paper, paper.length+1);
paper[paperNum] = new TestPaper(paperNum+1);
for(int j=0;j<ParaseInput.MatchingQuestionNum(line).length;j++) {
for(int i=0;i<questionNum;i++) {
if(question[i].num==Integer.parseInt(ParaseInput.MatchingQuestionNum(line)[j])) {
paper[paperNum].inputQuestion(question[i].num, question[i]);
paper[paperNum].inputQuestionGrace(Integer.parseInt(ParaseInput.MatchingQuestionGrace(line)[j]));
}
}
}
}
//如果输入答案
if(line.startsWith("#S:")) {
answers = Arrays.copyOf(answers, answers.length+1);
for(int i=0;i<paperNum;i++) {
if(paper[i].number==(Integer.parseInt(InputMatching.answerNumMatching(line)))) {
answers[answerNum] = new AnswerPaper(paper[i]);
answers[answerNum].InputAnswer(InputMatching.answerMatching(line));
}
}
}
line = input.nextLine();
}
//输出分数是否100
for(int i=0;i<paperNum;i++) {
paper[i].InputGrace();
}
//输出题目与答案
for(int i=0;i<answerNum;i++) {
for(int j=0;j<paper[i].questionNum;j++) {
if(j>answers[i].answers.length) {
System.out.println("answer is null");
continue;
}
System.out.println(answers[answerNum].paper.questions[j].cotent+"~"+answers[answerNum].answers[j]+"~"+answers[answerNum].paper.questions[j].standardAnswer.equals(answers[answerNum].answers[j]));
}
for(int k=0,grace=0;k<paper[i].questionNum;k++) {
if(k>answers[i].answers.length) {
System.out.printf("0");
if(k!=paper[i].questionNum-1) {
System.out.printf(" ");
}
else {
System.out.printf("~");
}
}
if(answers[answerNum].paper.questions[k].standardAnswer.equals(answers[answerNum].answers[k])) {
System.out.printf("%d", answers[answerNum].paper.questionsGrace[k]);
grace+=answers[answerNum].paper.questionsGrace[k];
if(k!=paper[i].questionNum-1) {
System.out.printf(" ");
}
else {
System.out.printf("~");
}
}
else {
System.out.printf("0");
if(k!=paper[i].questionNum-1) {
System.out.printf(" ");
}
else {
System.out.printf("~");
}
}
System.out.println(grace);
}
}
input.close();
}
}
代码分析
这次代码十分不完善,难以解决这道题
这段代码是在第二次代码上进行了略微升级,同样的是Question类存储题目信息,再有TestPaper类存储试卷信息并由存储的试卷信息来匹配题目,在使用Question[]数组来存储时均需要的Question题目信息,然后是AnswerPaper类通过试卷号TestPaperNumber来匹配试卷,再将试卷TestPaper保存到AnswerPaper中去。
关于对第二次的迭代:
增加了更多的方法PrintQ_A(int num) questionInput(String question) matchingStandardAnswers(String answer) markQuestion(int num,String answer) printQuestions()等等各种方法和在各个class类中增加元素来保存各种信息,但依旧难以解决这一问,这段代码的基础框架不够完美,难以进行更上一层的迭代。
踩坑心得
这三次pta对我来说十分困难,虽然是从易到难,但每一次的难度跨度都大大超过了我的预期,是我本能的抗拒这些题,但是我仍然坚持着写了下了,我意识到了尽管我没能很好的解决这些问题,但是我依旧收获颇多。
1.正则表达式的使用 我经常失误,matcher.find()与matcher.group()的使用,应该搭配上while循环使用,还有split对于规律的输入非常好用,但一旦输入变得复杂,需要考虑的问题就会急剧增加,每一次切割所要顾虑的String[] 字符组将呈指数型增加。
2.对class类的使用 刚开始第一次pta最后一题,我并没有使用class,而是一个Main主函数走天下,这使得我的主函数十分复杂,难以修改,牵一发而动全身,因此写程序对于class类得使用非常重要。
3.boolean型的使用 因为在c语言的学习中,判断一直认为是true为除0外的其他整数,而false为0,导致对boolean型返回值方法的使用十分别扭,在好几次错误下才得以改正。
4.程序设计结构很重要,我的代码因为结构不行难以修改,后续修改牵一发而动全身,常常改一个错误,要出现一堆错误,导致极其难修改,甚至不敢修改。
5.方法名,变量名,类名的命名应要清晰 刚开始我的代码变量名 类名 方法名取名十分随意 常常是 j jj k i等等当代码写长的时候 回头去看完全分不清这段代码的作用,只能从头看这段代码,十分浪费时间不说,如果代码过长,看到一半甚至可能搞混各种名字的意义,导致代码自己都看不懂,改又改不了,看又看不懂。只有规范自己才能方便自己。
6.代码的注释也十分重要 我的代码一般很少写注释,每次使用方法都要去看方法的代码,来看它的作用是什么,怎么使用,参数的作用又是什么,同样浪费时间,影响写代码的效率,甚至导致代码完全看不懂。
7.class类进行适当的切割 类的切割十分关键,这关乎代码的复用性 维护难易 ,类太多难以找到具体要用的class类,类太少就如同一个Main主函数走天下一样,难以修改,难以维护,甚至可能自己都看不懂一段代码的作用,所以class类的分割十分重要。
8.不要固步自封 时时刻刻学习新方法很重要在前几次代码我分答案 试卷 问题通常都是split一切再切 但学了startWith()就会极为简单,还有数组的合适长度,学了Arrays.copyOf()可以随时延长数组十分方便。
9.不要刻意去找规律 有时刻意去找规律反而会影响自己,在第一次pta最后一题 规律太容易找了,找到后我的代码完全按照规律来写,在到了第二次第三次 规律难找了,我的原始代码很难在其基础上进行迭代,只能重新写一串代码,因此不要刻意去找规律,要留足迭代的空间,要搭建结构好的代码。
改进建议
1.结构 结构意味着代码的提升空间 能否迭代
2.命名规则 规范自身才能方便自身
3.注释 好的注释能省掉大量复看代码的时间
4.活到老,学到老 每一次学习的过程中都有可能发现一种甚至多种能够更快解决当下问题的快捷方法
5.温故而知新 对于曾经学过的知识要勤加练习,可能发现自身的不足甚至发掘出更多用法
总结
三次Pta练习带给我很多个痛苦的夜晚,但也教会了我很多,这是简单的题目难以做到,一次尝试Pta难题的过程就像攀登一座难以望到顶的高山,但当你解决它的时候,那种成就感也是其他题目给不了的,在攀登的过程中,其中风景是独一无二的。
关于前三次pta的总结的更多相关文章
- 对前三次PTA作业的总结
一.前言 通过对前三次PTA作业的总结,其中蕴含着不少知识点.它让真正开始接触Java的我一点一点的渗入其中.其包含的知识点有Java代码的大体结构,例如: public class Main{ pu ...
- JAVA pta 前三次大作业回顾与分析
一.前言:总结三次题目集的知识点.题量.难度等情况 今年初次接触java,通过这三次大作业的练习,我对java有了一定的认识,相比于其他编程语言来说,java更复杂,要求也更严谨,需要掌握的知识也更多 ...
- 用python+selenium抓取知乎今日最热和本月最热的前三个问题及每个问题的首个回答并保存至html文件
抓取知乎今日最热和本月最热的前三个问题及每个问题的首个回答,保存至html文件,该html文件的文件名应该是20160228_zhihu_today_hot.html,也就是日期+zhihu_toda ...
- <记录学习>(前三天)京东页面各种注意点
培训学校第1到3天先学习HTML现在流行的是HTML5,目前学习的是HTML5规范.(给有基础一定的人学习)前三天学习的是京东页面的编写,和以前写的不同,页面看上去和自己写的一样,但老师讲的还是有很多 ...
- jq最新前三篇文章高亮显示
/*---------最新前三篇文章高亮显示-------------*/ function latest(){ var color_arr=new Array( "blue", ...
- NOIP2008提高组(前三题) -SilverN
此处为前三题,第四题将单独发布 火柴棒等式 题目描述 给你n根火柴棍,你可以拼出多少个形如“A+B=C”的等式?等式中的A.B.C是用火柴棍拼出的整数(若该数非零,则最高位不能是0).用火柴棍拼数字0 ...
- 【HDOJ】前三百留念
4个月不到的时间,终于刷到了HDOJ前三百.肯定还不够,好多基本的算法还不了解.还得继续学习.以此留念,假期目标是前一百.
- 对编程语言的需求总结为四个:效率,灵活,抽象,生产率(C++玩的是前三个,Java和C#玩的是后两个)
Why C++ ? 王者归来(转载) 因为又有人邀请我去Quora的C2C网站去回答问题去了,这回是 关于 @laiyonghao 的这篇有点争议的博文<2012 不宜进入的三个技术点>A ...
- 使用批处理bat作为日期系统日期的前三天
在管理server它经常是依据一天来推断载日期系统日志文件,例如,上周五,周一的需要上传日志.上传日志的日期前一天,日志文件命名的日期.这需要获得的日期的前三天.或之前n当天日期. 批量绑定vbs可以 ...
- 根据PV统计出前三的热门板块,并统计出热门板块下的用户数--方式一
根据PV统计出前三的热门板块,并统计出热门板块下的用户数--方式一 测试数据 java代码 package com.hzf.spark.study; import java.util.ArrayLis ...
随机推荐
- 阿里云拨测:主动探测Web应用质量,助力提升用户体验
简介: 阿里云拨测是一种针对互联网应用(Web页面.网络链路等)进行应用性能和用户体验监测的服务,无需嵌码即可为云上用户提供开箱即用的企业级主动拨测式应用监测解决方案. 随着中国数字化经济的蓬勃发展, ...
- 一文理解 K8s 容器网络虚拟化
简介:本文需要读者熟悉 Ethernet(以太网)的基本原理和 Linux 系统的基本网络命令,以及 TCP/IP 协议族并了解传统的网络模型和协议包的流转原理.文中涉及到 Linux 内核的具体实现 ...
- [FAQ] Phpstorm 代码提示功能失效问题
如果是之前有代码提示,中间突然不出现提示了,那么考虑重建一下项目索引. 示例: Refer:Phpstorm代码提示 Link:https://www.cnblogs.com/farwish/p/13 ...
- Postergresql常见操作
Postergresql常见操作 1. 安装部署 略 2. 登录数据库 查看版本 ## 以管理员身份 postgres 登陆,然后通过#psql -U postgres#sudo -i -u post ...
- 01.windows 环境设置
windows下可以安装Git工具, 使用git bash操作 Windows 10 环境下,通过-/.bash_profile 设置 git bash 别名: 打开 git bash,需切换到当前用 ...
- rails角本启动和停止
start.sh #!/bin/bash nohup rails s Puma -d >> run_log.log 2>&1 & stop.sh #!/bin/bas ...
- 飞桨PaddleLite架构研读
一.架构全景图 二.源码详细解读 1. Lite体系下似乎有多种 op_desc/program_desc 的定义,之间的关系是什么?这样设计的背景和好处是什么? model_parser目录下,包含 ...
- Sublime Text 3 初试牛刀
每次我在其他视频网站上看学习视频的时候,看着老师用的编辑器高大上档次,而我一般用Notepad,和Dreamweaver去编辑网页,需要每一行代码,打进去,效率低.最近看到sublime编辑器,在网上 ...
- Mybatis Plus的@TableId标签
@TableId1.如果数据库字段设成user_id在初始生成后,在代码中会变成userId,不会设置成主键使用**@TableId(value="user_id",type = ...
- 远程控制软件 TeamViewer 的局限性和替代方案
TeamViewer 公司创建于2005年,总部位于德国,客户遍及全球,其中企业用户居多,其各方面性能都很不错,但价格却非常贵.针对个人用户,TeamViewer 提供免费版软件,但时不时会提示&qu ...