PTA前三次作业总结
1. 前言:
第一次作业比较简单,虽然题目数量比较多,但是内容却比较简单😋,主要是让我们熟悉java的一些基本语法,涉及到的难点主要是对String类的一些方法的使用。第二次作业只有3道题,难度也不是很高,主要还是考察对String类的运用。第三次作业难度就上来了😰,虽然还是只有三道题(一道大题拆成三道),
2. 设计与分析:
第一次作业
由于第一次作业比较简单,故不专门对某个题进行分析,主要讲用到的关于String类的一些方法。主要是三个方法:substring,equals和chacharAt。substring用于截取字符串的方法,equals是字符串进行比较的方法,而charAt是取字符串某一位置的字符,在学号识别这道题中比较方便。通过这次作业也能让我们简单体会到面向过程与面向对象的区别。
第二次作业
7-2 串口字符解析
题目: RS232是串口常用的通信协议,在异步通信模式下,串口可以一次发送5-8位数据,收发双方之间没有数据发送时线路维持高电平,相当于接收方持续收到数据“1”(称为空闲位),发送方有数据发送时,会在有效数据(5~8位,具体位数由通信双方提前设置)前加上1位起始位“0”,在有效数据之后加上1位可选的奇偶校验位和1位结束位“1”。请编写程序,模拟串口接收处理程序,注:假定有效数据是8位,奇偶校验位采用奇校验。
输入格式:
由0、1组成的二进制数据流。例如:11110111010111111001001101111111011111111101111
输出格式:
过滤掉空闲、起始、结束以及奇偶校验位之后的数据,数据之前加上序号和英文冒号。
如有多个数据,每个数据单独一行显示。
若数据不足11位或者输入数据全1没有起始位,则输出"null data",
若某个数据的结束符不为1,则输出“validate error”。
若某个数据奇偶校验错误,则输出“parity check error”。
若数据结束符和奇偶校验均不合格,输出“validate error”。
如:11011或11111111111111111。
例如:
1:11101011
2:01001101
3:validate error
输入样例:
在这里给出一组输入。例如:
1111011101011111111111
输出样例:
在这里给出相应的输出。例如:
1:11101011
输入样例1:
在这里给出一组输入。例如:
11110111010111111001001101111111011111111101111
输出样例1:
在这里给出相应的输出。例如:
1:11101011
2:01001101
3:validate error
输入样例2:
输入数据不足11位。例如:
111101
输出样例2:
在这里给出相应的输出。例如:
null data
输入样例3:
输入数据全1没有起始位。例如:
1111111111111111
输出样例3:
在这里给出相应的输出。例如:
null data
输入样例4:
输入数据全1没有起始位。例如:
111101110101111111101111111101
输出样例4:
在这里给出相应的输出。例如:
1:11101011
2:parity check error
输入样例5:
两组数据结束符和奇偶校验均不合格。例如:
111000000000000011100000000000000
输出样例5:
在这里给出相应的输出。例如:
1:validate error
2:validate error
输入样例6:
两组数据,数据之间无空闲位。例如:
1110000000001100111000001
输出样例6:
在这里给出相应的输出。例如:
1:00000000
2:01110000
试题分析: 首先通过题目我们可以知道,通信数据的有效位设定为8位,在有效数据的前面加一位起始位0,有效数据的后一位奇偶校验位和一位结束位1。本题采用奇校验,也就是这11位组成的一个数据的1的个数为偶数。对于这道题目,首先输入的01字符串数目不能小于11,因为一个满足题目的字符串至少有11位,如果输入小于11,那必然不满足,题目中也给出相应输出。其次在这么长一段字符中我们该如何进行检索呢?我用的是笨方法,对字符串进行遍历,去寻找起始位0(记得遍历前先判断有没有0,也就是题目全1的情况),找到后再去遍历之后的10位(当然,要判断字符串剩余长度是否足够),去看数据是否满足奇校验,是否以1作为结束位,将结果按题目条件输出即可。判断完这一段后,直接跳转到这后一位即可,通过这样循环往复对整个字符串完成遍历,对每一段的结果进行输出。这道题目说实话难度也不高,难点可能在于读懂题目的意思,如多少位组成一个小集合你去判断(11位),什么是奇校验等,读懂了思路其实不难。
源代码展示:
查看代码
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
String s;
s = in.nextLine();
boolean flag = true;
int cnt = 0,num = 1;
if(s.length() < 11){
System.out.println("null data");
return;
}
for(int i=0; i < s.length(); i++){
if(s.charAt(i) == '0'){
flag = false;
break;
}
}
if(flag){
System.out.println("null data");
return;
}
for(int i=0; i < s.length() ; i++){
if(s.charAt(i) == '0' ){
if(i + 10 >= s.length() ){
//System.out.println(num+":"+"validate error");
return;
}
for(int j = i; j <= i+9; j++){
if(s.charAt(j) == '1')
cnt++;
}
if(s.charAt(i+10) != '1' && cnt % 2 ==0){
System.out.println(num+":"+"validate error");
num++;
}
else if(s.charAt(i+10) != '1'){
System.out.println(num+":"+"validate error");
num++;
}
else if(cnt % 2 ==0){
System.out.println(num+":"+"parity check error");
num++;
}
else{
String str = s.substring(i+1,i+9);
System.out.println(num+":"+str);
num++;
}
//System.out.println(" "+cnt);
cnt = 0;
i += 10;
}
}
}
}
类图:
SourceMonitor生成的报表内容:
代码分析总结: 在这之后学到了正则表达式,使用正则表达式可进一步简化程序,复用性也会更好。
第三次作业
7-1 点线形系列1-计算两点之间的距离
题目:输入连个点的坐标,计算两点之间的距离
输入格式:
4个double类型的实数,两个点的x,y坐标,依次是x1、y1、x2、y2,两个点的坐标之间以空格分隔,每个点的x,y坐标以英文“,”分隔。例如:0,0 1,1或0.1,-0.3 +3.5,15.6。
若输入格式非法,输出"Wrong Format"。
若输入格式合法但坐标点的数量超过两个,输出“wrong number of points”。
输出格式:
计算所得的两点之间的距离。例如:1.4142135623730951
输入样例:
整数输入。例如:
0,0 1,1
输出样例:
在这里给出相应的输出。例如:
1.4142135623730951
输入样例1:
带符号double类型实数输入。例如:
+2,-2.3 0.9,-3.2
输出样例1:
在这里给出相应的输出。例如:
1.42126704035519
输入样例2:
格式非法。例如:
++2,-2.3 0.9,-3.2
输出样例2:
在这里给出相应的输出。例如:
Wrong Format
输入样例3:
点的数量超过两个。例如:
+2,-2.3 0.9,-3.2 +2,-2.3
输出样例3:
在这里给出相应的输出。例如:
wrong number of points
试题分析: 第一道题相对简单,主要考察正则表达式,也是后面两题的基础。思路主要是先将所有输入拆成一个个待检验的坐标,再将待检验的坐标拆成待检验的数,完成这一步用到了String类的sqlit方法,通过对“ ”和“,”进行分组达到拆分的目的。然后对每个单独的数据进行正则表达式的判别就简单多了。这里附上我的正则表达式 ("[+-]?(0|(0\\.[0-9]+)?|[1-9][0-9]*(\\.[0-9]+)?)")
。完成这一步基本上完成了绝大部分了,然再将判别好了的x,y用Double.valueOf方法转成double类型存起来就得到点的坐标了(当然,不符合情况的非法输入就在match里排除了),再用两点间的距离公式求出就行了(不会有人公式不会吧😨)。
源代码展示:
查看代码
import com.sun.jdi.DoubleValue;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
String s = in.nextLine();
String p[] = s.split(" ");
boolean flag = true;
for (String x:p) {
String num[] = x.split(",");
for (String y:num) {
if(!y.matches("[+-]?(0|(0\\.[0-9]+)?|[1-9][0-9]*(\\.[0-9]+)?)"))
flag = false;
}
}
if (!flag){
System.out.println("Wrong Format");
return;
}
if(p.length > 2){
System.out.println("wrong number of points");
return;
}
double x1,y1,x2,y2;
String num1[] = p[0].split(",");
String num2[] = p[1].split(",");
x1 = Double.valueOf(num1[0]);y1 = Double.valueOf(num1[1]);
x2 = Double.valueOf(num2[0]);y2 = Double.valueOf(num2[1]);
System.out.println(Math.sqrt(Math.abs( (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2) )) );
}
}
类图:
SourceMonitor生成的报表内容:
代码分析总结: 因为还刚接触java,对面向对象还不是很理解,所有没有专门分一个类写,所有导致后面又写了一遍重复的东西,代码复用性不高,且第一题缺少对一个坐标里包含大于一个“,”判断的测试点,导致我沿用第一题的代码被卡了很久😭,大家引以为戒啊。
7-2 点线形系列2-线的计算
题目: 用户输入一组选项和数据,进行与直线有关的计算。选项包括:
1:输入两点坐标,计算斜率,若线条垂直于X轴,输出"Slope does not exist"。
2:输入三个点坐标,输出第一个点与另外两点连线的垂直距离。
3:输入三个点坐标,判断三个点是否在一条线上,输出true或者false。
4:输入四个点坐标,判断前两个点所构成的直线与后两点构成的直线是否平行,输出true或者false.
5:输入四个点坐标,计算输出前两个点所构成的直线与后两点构成的直线的交点坐标,x、y坐标之间以英文分隔",",并输出交叉点是否在两条线段之内(不含四个端点)的判断结果(true/false),判断结果与坐标之间以一个英文空格分隔。若两条线平行,没有交叉点,则输出"is parallel lines,have no intersection point"。
输入格式:
基本格式:选项+":"+坐标x+","+坐标y+" "+坐标x+","+坐标y。
例如:1:0,0 1,1
如果不符合基本格式,输出"Wrong Format"。
如果符合基本格式,但输入点的数量不符合要求,输出"wrong number of points"。
不论哪个选项,如果格式、点数量都符合要求,但构成任一条线的两个点坐标重合,输出"points coincide",
输出格式:
见题目描述。
输入样例1:
选项1,两点重合。例如:
1:-2,+5 -2,+5
输出样例:
在这里给出相应的输出。例如:
points coincide
输入样例2:
选项1,斜率无穷大的线。例如:
1:-2,3 -2,+5
输出样例:
在这里给出相应的输出。例如:
Slope does not exist
输入样例3:
选项1,斜率无穷大。例如:
1:-2,3 -2,+5
输出样例:
在这里给出相应的输出。例如:
Slope does not exist
输入样例4:
选项1,符合格式输入,带符号/不带符号数混合。例如:
1:-2.5,3 -2,+5.3
输出样例:
在这里给出相应的输出。例如:
4.6
输入样例5:
选项2,计算第一个点到另外两点连线的垂直距离。例如:
2:0,1 1,0 2,0
输出样例:
在这里给出相应的输出。例如:
1.0
输入样例6:
选项3,判断三个点是否在一条线上。例如:
3:0,1 2,2 5,3
输出样例:
在这里给出相应的输出。例如:
false
输入样例7:
选项4,判断两条线是否平行。例如:
4:0,1 0,2 2,1 3,0
输出样例:
在这里给出相应的输出。例如:
false
输入样例8:
选项5,判断两条线的交点。例如:
5:0,0 -1,-1 0,2 3,-1
输出样例:
在这里给出相应的输出,交点坐标之间以英文","分隔,判断结果与坐标之间以一个英文空格分隔。例如:
1.0,1.0 true
输入样例9:
选项5,判断两条线的交点。但两条线平行例如:
5:0,0 -1,-1 2,3 3,4
输出样例:
在这里给出相应的输出,交点坐标之间以英文","分隔,判断结果与坐标之间以一个英文空格分隔。例如:
is parallel lines,have no intersection point
试题分析: 第二道题难度一下就上来了,5种输入情况,如果采用面向过程的编程将会很复杂,建议用面向对象的方法写。首先通过题目知道,本题是关于点和线的,那么我们可以创建两个类,一个点类一个线类。点的属性很明显就是其坐标x,y,而线是由点构成的,所有线的属性可以包含两个点,除了这些,为了符合题目,我还设定了A,B,C三个属性代表直线一般式的三个系数以及k和b代表直线点斜式的式子(这里建议用一般式,k和b可以不用)。属性有了,那我们来看方法,首先case1需要求直线斜率,很明显,这可以作为直线的一个方法写在直线类中,公式也很简单(y1-y2)/(x1-x2)即可。case2求点到直线的距离,这也可以作为直线类中的一个方法,公式也很简单 d=│AXo+BYo+C│/√(A²+B²),(听说这里用点斜式可能被卡)。case3求是否共线有不少方法,如向量相乘,代入解析式等,具体方法看自己选取,当然这里也作为直线的一个方法。(注意公式可适当设置误差)。case4判断是否平行就很简单了,也可以让我们直观的感受到类的好处,我们可以使用求斜率的方法判断斜率是否相等以此来完成判断平行的方法,如果之前没有完善的构建类,这里又要把之前的代码复制一遍,代码的复用性和可读性都大大降低。case5的直线求交点同样可以先调用之前判断平行的方法决定是否有交点,若不平行只要用数学公式就可以直接求到交点。 公式:
当然除了对上述每一个case的情况的分析,本题还需重点关注的东西就是格式问题,我为此建了一个Check类用于检查格式问题,而大体方法则是沿用上题的思路,这里再一次展示了类的好处,如果上题我建好了,这题就不用再写直接用了。
源代码展示:
查看代码
import java.util.Scanner;
import static java.lang.Double.POSITIVE_INFINITY;
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
String input = in.nextLine();
String s = input.substring(2);
Check check = new Check();
check.setInput(s);
//if(!check.CheckFormat()) return;
if(input.charAt(0) == '1' && input.charAt(1) == ':'){
Line line1 = new Line();
if(!check.CheckFormat(2)) return;
//if(check.CheckP(2)) return;
line1.setM( check.GetStingPoints(0) ) ;
line1.setN( check.GetStingPoints(1) ) ;
if(!line1.CheckLine())
return;
if(line1.slope() == POSITIVE_INFINITY){
System.out.println("Slope does not exist");
}
else {
System.out.println(line1.slope());
}
}
else if(input.charAt(0) == '2' && input.charAt(1) == ':'){
Line line2 = new Line();
Points points2 = new Points();
if(!check.CheckFormat(3)) return;
//if(check.CheckP(3)) return;
points2 = check.GetStingPoints(0);
line2.setM( check.GetStingPoints(1) ) ;
line2.setN( check.GetStingPoints(2) ) ;
if(!line2.CheckLine())
return;
line2.SetLine();
System.out.println(line2.distance(points2));
}
else if(input.charAt(0) == '3' && input.charAt(1) == ':'){
Line line3 = new Line();
Line line3_1 = new Line();
Line line3_2 = new Line();
Points points3 = new Points();
if(!check.CheckFormat(3)) return;
// if(check.CheckP(3)) return;
points3 = check.GetStingPoints(0);
line3.setM( check.GetStingPoints(1) ) ;
line3.setN( check.GetStingPoints(2) ) ;
if(!line3.CheckLine() )
return;
line3.SetLine();
if(line3.IsCollinear(points3)){
System.out.println("true");
}
else
System.out.println("false");
}
else if(input.charAt(0) == '4' && input.charAt(1) == ':'){
Line line4_1 = new Line();
Line line4_2 = new Line();
if(!check.CheckFormat(4)) return;
//if(check.CheckP(4)) return;
line4_1.setM( check.GetStingPoints(0) ) ;
line4_1.setN( check.GetStingPoints(1) ) ;
line4_2.setM( check.GetStingPoints(2) ) ;
line4_2.setN( check.GetStingPoints(3) ) ;
if(!line4_1.CheckLine() || !line4_2.CheckLine())
return;
if(line4_1.IsParallel(line4_2))
System.out.println("true");
else
System.out.println("false");
}
else if(input.charAt(0) == '5' && input.charAt(1) == ':'){
Points points5 = new Points();
Line line5_1 = new Line();
Line line5_2 = new Line();
if(!check.CheckFormat(4)) return;
//if(check.CheckP(4)) return;
line5_1.setM( check.GetStingPoints(0) ) ;
line5_1.setN( check.GetStingPoints(1) ) ;
line5_2.setM( check.GetStingPoints(2) ) ;
line5_2.setN( check.GetStingPoints(3) ) ;
if(!line5_1.CheckLine() || !line5_2.CheckLine())
return;
line5_1.SetLine();line5_2.SetLine();
if(line5_1.IsParallel(line5_2))
System.out.println("is parallel lines,have no intersection point");
else {
points5 = line5_1.CrossoverPoint(line5_2);
System.out.print(points5.getX()+","+points5.getY()+" ");
if(line5_1.IsReallyCollinear(points5) || line5_2.IsReallyCollinear(points5))
System.out.println("true");
else
System.out.println("false");
}
}
else {
System.out.println("Wrong Format");
}
}
}
class Check {
private String input;
public void setInput(String input) {
this.input = input;
}
public String getInput() {
return input;
}
public boolean CheckFormat(int index) {
boolean flag = true;
int cnt = 0;
String p[] = input.split(" ");
for (String x:p) {
String num[] = x.split(",");
if(num.length != 2){
System.out.println("Wrong Format");
return false;
}
for (String y:num) {
if(!y.matches("^[+-]?(0|(0\\.\\d+)?|[1-9][0-9]*(\\.\\d+)?)$"))
flag = false;
}
cnt++;
}
//System.out.println(input);
if(!flag){
System.out.println("Wrong Format");
return false;
}
if(cnt > index || cnt < index ){
System.out.println("wrong number of points");
return false;
}
return true;
}
public Points GetStingPoints(int index) {
Points a = new Points();
String p[] = input.split(" ");
String num[] = p[index].split(",");
a.setX(Double.valueOf(num[0]));
a.setY(Double.valueOf(num[1]));
return a;
}
}
class Line {
private Points m;
private Points n;
private double k;
private double b;
private double A;
private double B2;
private double C;
public void setA(double a) {
A = a;
}
public void setB2(double b2) {
B2 = b2;
}
public void setC(double c) {
C = c;
}
public void setB(double b) {
this.b = b;
}
public void setK(double k) {
this.k = k;
}
public double getA() {
return A;
}
public double getB2() {
return B2;
}
public double getC() {
return C;
}
public double getB() {
return b;
}
public double getK() {
return k;
}
public Points getN() {
return n;
}
public Points getM() {
return m;
}
public void setM(Points m) {
this.m = m;
// System.out.println("m :"+this.m.getX()+" "+this.m.getY());
}
public void setN(Points n) {
this.n = n;
// System.out.println("n :"+this.n.getX()+" "+this.n.getY());
}
public boolean CheckLine(){
if(m.getX() == n.getX() && m.getY() == n.getY()){
System.out.println("points coincide");
return false;
}
return true;
}
public double slope(){
if(m.getX() == n.getX())
return POSITIVE_INFINITY;
else
return ( m.getY() - n.getY() ) / (m.getX() - n.getX() );
}
public void SetLine(){
setK(Math.round(slope()));
setB(Math.round(m.getY() - m.getX() * getK()) );
setA(m.getY() - n.getY());
setB2(n.getX() - m.getX());
setC( m.getX() * n.getY() - n.getX() * m.getY() );
}
public double distance(Points a){
return Math.abs( getA() * a.getX() + getB2() * a.getY() +getC() ) / Math.sqrt( getA() * getA() + getB2() * getB2() ) ;
}
public Points CrossoverPoint(Line l){
Points CroPoint = new Points();
if(!IsParallel(l)){
double x1 = ( getB2() * l.getC() - l.getB2() * getC() ) / (getA() * l.getB2() - l.getA() * getB2());
double y1 = ( l.getA() * getC() - getA() * l.getC() ) / (getA() * l.getB2() - l.getA() * getB2());
CroPoint.setX( x1 );
CroPoint.setY( y1 );
//System.out.println( CroPoint.getX()+" "+CroPoint.getY() );
return CroPoint;
}
// else
return null;
}
public boolean IsCollinear(Points a){
if( m.getX() == n.getX() ){
if(m.getX() == a.getX())
return true;
else
return false;
}
if(Math.round( getA() * a.getX() + getB2() * a.getY() + getC() ) == 0)
return true;
return false;
}
public boolean IsReallyCollinear(Points a){
if(a.getX() > Math.min(m.getX(),n.getX()) && a.getX() < Math.max(m.getX(),n.getX()) && a.getY() > Math.min(m.getY(),n.getY()) && a.getY() < Math.max(m.getY(),n.getY()))
return true;
else
return false;
}
public boolean IsParallel(Line l){
if( this.slope() == l.slope() ){
return true;
}
else
return false;
}
}
class Points {
private double x;
private double y;
public Points(){
}
public Points(double x,double y){
this.x = x;
this.y = y;
}
public void setX(double x){
this.x = x;
}
public void setY(double y){
this.y = y;
}
public double getX(){
return this.x;
}
public double getY(){
return this.y;
}
public boolean CheckPoints(Points p){
if( getX() == p.getX() && getY() == p.getY()){
System.out.println("points coincide");
return true;
}
else
return false;
}
public double PointsDistance(double x,double y){
return Math.sqrt(Math.abs( (this.x - x) * (this.x - x) + (this.y - y) * (this.y - y) ));
}
}
类图:
SourceMonitor生成的报表内容:
代码分析总结: 通过这道题目,深刻让我意识到了类的重要性,同时我对类有了基本的了解,不过代码有些地方可能编写不够完善,比如main中重复的部分。
7-3 点线形系列3-三角形的计算
题目: 用户输入一组选项和数据,进行与三角形有关的计算。选项包括:
1:输入三个点坐标,判断是否是等腰三角形、等边三角形,判断结果输出true/false,两个结果之间以一个英文空格符分隔。
2:输入三个点坐标,输出周长、面积、重心坐标,三个参数之间以一个英文空格分隔,坐标之间以英文","分隔。
3:输入三个点坐标,输出是钝角、直角还是锐角三角形,依次输出三个判断结果(true/false),以一个英文空格分隔,
4:输入五个点坐标,输出前两个点所在的直线与三个点所构成的三角形相交的交点数量,如果交点有两个,则按面积大小依次输出三角形被直线分割成两部分的面积。若直线与三角形一条线重合,输出"The point is on the edge of the triangle"
5:输入四个点坐标,输出第一个是否在后三个点所构成的三角形的内部(输出in the triangle/outof triangle)。
必须使用射线法,原理:由第一个点往任一方向做一射线,射线与三角形的边的交点(不含点本身)数量如果为1,则在三角形内部。如果交点有两个或0个,则在三角形之外。若点在三角形的某条边上,输出"on the triangle"
输入格式:
基本格式:选项+":"+坐标x+","+坐标y+" "+坐标x+","+坐标y。点的x、y坐标之间以英文","分隔,点与点之间以一个英文空格分隔。
输出格式:
基本输出格式见每种选项的描述。
异常情况输出:
如果不符合基本格式,输出"Wrong Format"。
如果符合基本格式,但输入点的数量不符合要求,输出"wrong number of points"。
如果输入的三个点无法构成三角形,输出"data error"。
注意:输出的数据若小数点后超过6位,只保留小数点后6位,多余部分采用四舍五入规则进到最低位。小数点后若不足6位,按原始位数显示,不必补齐。例如:1/3的结果按格式输出为 0.333333,1.0按格式输出为1.0
选项4中所输入线的两个点坐标重合,输出"points coincide",
输入样例1:
选项4,定义线的两点重合。例如:
4:1,0 1,0 0,0 2,0 4,0
输出样例:
在这里给出相应的输出。例如:
points coincide
输入样例2:
选项4,构成三角形的三个点在一条线上,无法构成三角形。例如:
4:1,0 0,2 0,0 0,0 4,0
输出样例:
在这里给出相应的输出。例如:
data error
输入样例3:
选项1,判断等腰、等边三角形。例如:
1:-2,0 2,0 0,4
输出样例:
两个判断结果。例如:
true false
输入样例4:
选项2,输出边长、面积、重心坐标。例如:
2:0,0 3,0 0,1
输出样例:
在这里给出相应的输出。例如:
7.162278 1.5 1.0,0.333333
输入样例5:
选项3,钝角、直角、锐角的判断。例如:
3:0,1 1,0 2,0
输出样例:
在这里给出相应的输出。例如:
true false false
输入样例6:
选项4,直线与三角形交点的数量等于2,输出数量值以及三角形被分割的两部分面积。例如:
4:1,0 0,2 0,0 0,2 4,0
输出样例:
在这里给出相应的输出。例如:
2 1.0 3.0
输入样例7:
选项4,直线与三角形交点的数量少于两个,只输出数量值。例如:
4:-1,0 1,2 0,1 0,-1 2,0
输出样例:
在这里给出相应的输出。例如:
1
输入样例8:
选项5,用射线法判断点是否在三角形内部。例如:
5:0.5,0.5 0,0 0,2 4,0
输出样例:
在这里给出相应的输出,交点坐标之间以英文","分隔,判断结果与坐标之间以一个英文空格分隔。例如:
in the triangle
输入样例9:
选项5,用射线法判断点是否在三角形内部。例如:
5:0,0 -1,-1 2,3 3,4
输出样例:
在这里给出相应的输出。例如:
outof the triangle
试题分析: 点构成线,线构成三角形,循序渐进,第三道题还是有难度的,也将前两题的铺垫全用上了。先说格式,直接调用第二题的Check类即可,不过这题额外多了一个保留小数的要求,我这提供一种思路。
四舍五入代码:
public static double sswr(double s)
{
String str=String.valueOf(s);
String substring = str.substring(str.indexOf(".") + 1);
int str_len;
if(substring.length()>6)
{
str_len=6;
}else {
str_len=substring.length();
}
String formats="%."+str_len+"f";
String out=String.format(formats,s);
double res=Double.parseDouble(out);
return res;
}
关于格式问题不再赘述,直接分析题目要求。(以下提到的方法自己写,这里不再详述)case1判断等腰还是等边,直接用直线中求长度方法分别求三条边判断即可。case2周长简单,面积可以底×高(点到直线距离)÷2,也可以海伦公式:
重心直接三个点坐标相加除以3即可。case3可以用三角函数判断(有公式,我没用这里就不附了)也可以用边判断,a * a +b * b和c*c进行比较,相等为直角,大于为锐角,小于钝角(注意先判断直角)。case4本题最难的地方,直线和三角形相交问题。0个交点和重合就不多说,平行和共线判断即可(重合疑似没测试点)。那么交点个数怎么求呢?我是用直线分别对三条边求交点得到三个点,先去重复点(其实我重复点直接不存了),然后判断点是否在三角形上(第二题判断点是否在线段上用到了),看得到交点的数量,1个没什么好说的,输出1就是。重点在于两个交点的情况,我这用的是一种简单单复用性不怎么好的方法,通过对三角形边的命名判断哪个顶点可以和直线构成三角形,再用大三角形面积减去小三角形面积得到另一部分面积。比如说交点在lab和lac上,那么很明显顶点a可以和直线构成三角形,就这样判断三次,谁满足取谁当顶点构成三角形算面积。我个人认为这个方法比较简单,毕竟不需要对过顶点的情况特判。(如果用判断点在直线左右侧的方法是需要特判的,当然我这只是抛砖引玉,希望大家能找到更好的方法)。case5我就介绍一下射线法吧,就是从要判断的点任意引出一条射线,和多边形边的交点为奇数个就在多边形内,偶数个就在外(包括0),实现的话可以对一固定方向引出,或者对360°都引出,具体看个人思路。
源代码展示:
查看代码
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
import java.util.Set;
import static java.lang.Double.POSITIVE_INFINITY;
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
String input = in.nextLine();
String s = input.substring(2);
Check check = new Check();
check.setInput(s);
//if(!check.CheckFormat()) return;
if(input.charAt(0) == '1' && input.charAt(1) == ':'){
if(!check.CheckFormat(3)) return;
Triangle triangle = new Triangle( check.GetStingPoints(0),check.GetStingPoints(1),check.GetStingPoints(2));
if( !triangle.IsTriangle() ) return;
triangle.SetTriangle();
triangle.IsSPTriangle();
}
else if(input.charAt(0) == '2' && input.charAt(1) == ':'){
if(!check.CheckFormat(3)) return;
Triangle triangle = new Triangle( check.GetStingPoints(0),check.GetStingPoints(1),check.GetStingPoints(2));
if( !triangle.IsTriangle() ) return;
triangle.SetTriangle();
System.out.println( Check.sswr(triangle.getPerimeter())+" "+Check.sswr(triangle.getArea())+" "+Check.sswr(triangle.getCentrePoint().getX())+","+Check.sswr(triangle.getCentrePoint().getY()));
// System.out.printf("%f %f %f,%f",(float) triangle.getPerimeter(),(float) triangle.getArea(),(float)triangle.getCentrePoint().getX(),(float)triangle.getCentrePoint().getY());
}
else if(input.charAt(0) == '3' && input.charAt(1) == ':'){
if(!check.CheckFormat(3)) return;
Triangle triangle = new Triangle( check.GetStingPoints(0),check.GetStingPoints(1),check.GetStingPoints(2));
if( !triangle.IsTriangle() ) return;
triangle.whichTriangle();
}
else if(input.charAt(0) == '4' && input.charAt(1) == ':'){
if(!check.CheckFormat(5)) return;
Triangle triangle = new Triangle( check.GetStingPoints(2),check.GetStingPoints(3),check.GetStingPoints(4));
Line line = new Line(check.GetStingPoints(0),check.GetStingPoints(1));
if( !line.CheckLine()) return;
if( !triangle.IsTriangle() ) return;
triangle.twoPointsOneTriangle(line);
//System.out.println("0");
}
else if(input.charAt(0) == '5' && input.charAt(1) == ':'){
if(!check.CheckFormat(4)) return;
Triangle triangle = new Triangle( check.GetStingPoints(1),check.GetStingPoints(2),check.GetStingPoints(3));
if( !triangle.IsTriangle() ) return;
Points points = new Points(check.GetStingPoints(0));
triangle.IsInTriangle1(points);
//System.out.println("on the triangle");
}
else {
System.out.println("Wrong Format");
}
}
}
class Check {
private String input;
public void setInput(String input) {
this.input = input;
}
public String getInput() {
return input;
}
public boolean CheckFormat(int index) {
boolean flag = true;
int cnt = 0;
String p[] = input.split(" ");
for (String x:p) {
String num[] = x.split(",");
if(num.length != 2){
System.out.println("Wrong Format");
return false;
}
for (String y:num) {
if(!y.matches("^[+-]?(0|(0\\.\\d+)?|[1-9][0-9]*(\\.\\d+)?)$"))
flag = false;
}
cnt++;
}
//System.out.println(input);
if(!flag){
System.out.println("Wrong Format");
return false;
}
if(cnt > index || cnt < index ){
System.out.println("wrong number of points");
return false;
}
return true;
}
public Points GetStingPoints(int index) {
Points a = new Points();
String p[] = input.split(" ");
String num[] = p[index].split(",");
a.setX(Double.valueOf(num[0]));
a.setY(Double.valueOf(num[1]));
return a;
}
public static double sswr(double s)
{
String str=String.valueOf(s);
String substring = str.substring(str.indexOf(".") + 1);
int str_len;
if(substring.length()>6)
{
str_len=6;
}else {
str_len=substring.length();
}
String formats="%."+str_len+"f";
String out=String.format(formats,s);
double res=Double.parseDouble(out);
return res;
}
}
class Triangle {
private Points a;
private Points b;
private Points c;
private Line lab;
private Line lbc;
private Line lac;
public Triangle(){
}
public Triangle(Points a,Points b,Points c){
this.a = a;
this.b = b;
this.c = c;
Line l1 = new Line(a,b);
Line l2 = new Line(a,c);
Line l3 = new Line(b,c);
lab = l1;
lac = l2;
lbc = l3;
SetTriangle();
}
public void setA(Points a) {
this.a = a;
}
public void setB(Points b) {
this.b = b;
}
public void setC(Points c) {
this.c = c;
}
public void setLbc(Line lbc) {
this.lbc = lbc;
}
public void setLab(Line lab) {
this.lab = lab;
}
public void setLac(Line lac) {
this.lac = lac;
}
public Points getA() {
return a;
}
public Points getB() {
return b;
}
public Points getC() {
return c;
}
public Line getLac() {
return lac;
}
public Line getLbc() {
return lbc;
}
public Line getLab() {
return lab;
}
public void SetTriangle(){
lab.SetLine();
lbc.SetLine();
lac.SetLine();
}
public double getPerimeter(){
return lab.getLength() + lbc.getLength() +lac.getLength();
}
/*public double getArea(){
double p = (getPerimeter()/ 2.0) ;
return Math.sqrt( p * (p - lab.getLength()) * (p - lac.getLength()) * (p - lbc.getLength()) );
}
*/
public double getArea(){
return lac.distance(b) * lac.getLength() / 2.0;
}
/*
public double getArea(){
double cos = (lab.getLength() * lab.getLength() + lac.getLength() * lac.getLength() - lbc.getLength() * lbc.getLength()) / (2.0 * lac.getLength() * lab.getLength() );
return Math.sqrt(1 - Math.pow(cos, 2)) * lab.getLength() * lac.getLength() * 0.5;
}*/
public Points getCentrePoint(){
Points CentrePoint = new Points();
double x1 = (a.getX() + b.getX() +c.getX() ) / 3;
double y1 = (a.getY() + b.getY() +c.getY() ) / 3;
CentrePoint.setX( x1);
CentrePoint.setY( y1);
return CentrePoint;
}
public void whichTriangle(){
double l1 = -1,l2 = -1,l3 = -1;
l1 = Math.min(lab.getLength(),Math.min(lbc.getLength(),lac.getLength()));
l3 = Math.max(lab.getLength(),Math.max(lbc.getLength(),lac.getLength()));
if (lab.getLength() == lbc.getLength() || lac.getLength() == lbc.getLength() || lab.getLength() == lac.getLength())
l2 = l1;
else {
if(lab.getLength() != l1 && lab.getLength() != l3)
l2 = lab.getLength();
else if(lac.getLength() != l1 && lac.getLength() != l3)
l2 = lac.getLength();
else
l3 = lbc.getLength();
}
int type = -1;
if ( Math.abs(l1 * l1 + l2 * l2 - l3 * l3) < 2)
type = 2;
else if( l1 * l1 + l2 * l2 > l3 * l3)
type = 3;
else
type = 1;
if(type == 1)
System.out.println("true false false");
else if(type == 2)
System.out.println("false true false");
else
System.out.println("false false true");
}
public boolean IsTriangle(){
if(lab.IsCollinear(c) || lac.IsCollinear(b) || lbc.IsCollinear(a) ){
System.out.println("data error");
return false;
}
if(lab.IsParallel(lac) || lab.IsParallel(lbc) || lbc.IsParallel(lac)){
System.out.println("data error");
return false;
}
return true;
}
public void IsSPTriangle(){
SetTriangle();
if(lab.getLength() == lbc.getLength() || lac.getLength() == lbc.getLength() || lab.getLength() == lac.getLength()){
System.out.print("true"+" ");
}
else
System.out.print("false"+" ");
if( lab.getLength() == lbc.getLength() && lab.getLength() == lac.getLength() ){
System.out.println("true");
}
else
System.out.println("false");
}
public void IsInTriangle(Points u){
Points stdpoint = new Points(u.getX()+300,u.getY()+1 );
List<Points> pointsList= new ArrayList<>();
pointsList.add(a);pointsList.add(b);pointsList.add(c);
List<Line> lineList = new ArrayList<>();
lineList.add(lac);lineList.add(lab);lineList.add(lbc);
List<Points> list = new ArrayList<>();
for(Points p : pointsList){
if(p.CheckPoints(u)){
System.out.println("on the triangle");
return ;
}
}
for (Line l : lineList){
if(l.IsReallyCollinear(u) && l.IsCollinear(u)){
System.out.println("on the triangle");
return;
}
}
Line line = new Line(u,stdpoint);
int cnt = 0;
for (Line l : lineList){
list.add(l.CrossoverPoint(line));
}
for (Points p : list){
boolean flag = true;
//System.out.println(p.getX() +" " + p.getY() + " " +u.getX() + " "+ u.getY());
if(p == null)
continue;
if(p.getX() > u.getX() && p.getY() > u.getY())
cnt++;
}
if(cnt % 2 != 0)
System.out.println("in the triangle");
else
System.out.println("outof the triangle");
}
public void IsInTriangle1(Points u){
double s1,s2,s3,s;
Triangle triangle1 = new Triangle(a,b,u);
Triangle triangle2 = new Triangle(a,c,u);
Triangle triangle3 = new Triangle(c,b,u);
s1 = triangle1.getArea();
//System.out.println(s1);
s2 = triangle2.getArea();
// System.out.println(s2);
s3 = triangle3.getArea();
// System.out.println(s3);
s = getArea();
//System.out.println(s);
if( (s1 + s2 + s3) - s > 0.01){
System.out.println("outof the triangle");
return;
}
List<Points> pointsList= new ArrayList<>();
pointsList.add(a);pointsList.add(b);pointsList.add(c);
List<Line> lineList = new ArrayList<>();
lineList.add(lac);lineList.add(lab);lineList.add(lbc);
for(Points p : pointsList){
if(p.CheckPoints(u)){
System.out.println("on the triangle");
return ;
}
}
for (Line l : lineList){
if(l.IsReallyCollinear(u) && l.IsCollinear(u)){
System.out.println("on the triangle");
return;
}
}
System.out.println("in the triangle");
}
public void twoPointsOneTriangle(Line line){
List<Line> lineList = new ArrayList<>();
lineList.add(lac);lineList.add(lab);lineList.add(lbc);
List<Points> pointsList= new ArrayList<>();
pointsList.add(a);pointsList.add(b);pointsList.add(c);
List<Points> list = new ArrayList<>();
int cnt = 0;
Points u;
for(Line l : lineList){
/*if(l.IsParallel(line) ){
if(l.IsReallyCollinearInclude(line.getM()) || l.IsReallyCollinearInclude(line.getN())){
System.out.println("The point is on the edge of the triangle");
return;
}
else{
System.out.println("0");
return;
}
}*/
u = l.CrossoverPoint(line);
//if(u!=null)
// System.out.println(u.getX()+","+u.getY());
boolean flag = false;
if( u != null){
for (Line line1 : lineList){
if(line1.IsReallyCollinearInclude(u) ){
flag = true;
}
}
// for (Points points : pointsList){
// if(points.CheckPoints(u))
// flag = true;
// }
for (Points p : list){
if( p.CheckPoints(u) ){
flag = false;
break;
}
}
// System.out.println(u.getX()+","+u.getY());
if(flag){
list.add(u);
cnt++;
}
}
}
if(cnt < 2){
System.out.println(cnt);
}
else {
double s1,s2,s;
System.out.print("2 ");
Line lline = new Line(list.get(0),list.get(1));
/* for(Points p : pointsList){
if(list.get(0).CheckPoints(p) || list.get(1).CheckPoints(p) ){
for(Points points : pointsList){
if(!p.CheckPoints(points)){
//System.out.println(points.getX() + ","+points.getY());
//System.out.println(list.get(0).getX() + ","+list.get(0).getY());
//System.out.println(list.get(1).getX() + ","+list.get(1).getY());
Triangle triangle1 = new Triangle(points,list.get(0),list.get(1));
s1 = triangle1.getArea();
s1 = Check.sswr(s1);
s = this.getArea();
s = Check.sswr(s);
s2 = s - s1;
s2 = Check.sswr(s2);
System.out.println(Math.min(s1,s2) + " " + Math.max(s1,s2));
return;
}
}
}
} */
Points p1 = list.get(0),p2 = list.get(1);
Points m;
if(lac.IsCollinear(p1) && lab.IsCollinear(p2) || lac.IsCollinear(p2) && lab.IsCollinear(p1))
m = a;
else if( lac.IsCollinear(p1) && lbc.IsCollinear(p2) || lac.IsCollinear(p2) && lbc.IsCollinear(p1) )
m = c;
else
m = b;
Triangle triangle1 = new Triangle(m,list.get(0),list.get(1));
s1 = triangle1.getArea();
s1 = Check.sswr(s1);
s = this.getArea();
s = Check.sswr(s);
s2 = s - s1;
s2 = Check.sswr(s2);
System.out.println(Math.min(s1,s2) + " " + Math.max(s1,s2));
}
}
}
class Line {
private Points m;
private Points n;
private double k;
private double b;
private double A;
private double B2;
private double C;
private double length;
public Line(){
}
public Line(Points m,Points n){
this.m = m;
this.n = n;
SetLine();
}
public void setLength() {
length = m.PointsDistance(n.getX(),n.getY());
}
public void setA(double a) {
A = a;
}
public void setB2(double b2) {
B2 = b2;
}
public void setC(double c) {
C = c;
}
public void setB(double b) {
this.b = b;
}
public void setK(double k) {
this.k = k;
}
public double getA() {
return A;
}
public double getB2() {
return B2;
}
public double getC() {
return C;
}
public double getB() {
return b;
}
public double getK() {
return k;
}
public Points getN() {
return n;
}
public Points getM() {
return m;
}
public double getLength() {
return length;
}
public void setM(Points m) {
this.m = m;
// System.out.println("m :"+this.m.getX()+" "+this.m.getY());
}
public void setN(Points n) {
this.n = n;
// System.out.println("n :"+this.n.getX()+" "+this.n.getY());
}
public boolean CheckLine(){
if(m.getX() == n.getX() && m.getY() == n.getY()){
System.out.println("points coincide");
return false;
}
return true;
}
public double slope(){
if(m.getX() == n.getX())
return POSITIVE_INFINITY;
else
return ( m.getY() - n.getY() ) / (m.getX() - n.getX() );
}
public void SetLine(){
setK(Check.sswr(slope()));
setB(Check.sswr(m.getY() - m.getX() * getK()) );
setA(m.getY() - n.getY());
setB2(n.getX() - m.getX());
setC( m.getX() * n.getY() - n.getX() * m.getY() );
setLength();
}
public double distance(Points a){
return Math.abs( getA() * a.getX() + getB2() * a.getY() +getC() ) / Math.sqrt( getA() * getA() + getB2() * getB2() ) ;
}
public Points CrossoverPoint(Line l){
Points CroPoint = new Points();
if(!IsParallel(l)){
double x1 = ( getB2() * l.getC() - l.getB2() * getC() ) / (getA() * l.getB2() - l.getA() * getB2());
double y1 = ( l.getA() * getC() - getA() * l.getC() ) / (getA() * l.getB2() - l.getA() * getB2());
//System.out.println( "crp "+CroPoint.getX()+","+CroPoint.getY() );
CroPoint.setX( x1 );
CroPoint.setY( y1 );
return CroPoint;
}
// else
return null;
}
public boolean IsCollinear(Points a){
if( m.getX() == n.getX() ){
if(m.getX() == a.getX())
return true;
else
return false;
}
if(Math.abs( getA() * a.getX() + getB2() * a.getY() + getC() ) < 0.01)
return true;
return false;
}
public boolean IsReallyCollinear(Points a){
if(a.getX() > Math.min(m.getX(),n.getX()) && a.getX() < Math.max(m.getX(),n.getX()) && a.getY() > Math.min(m.getY(),n.getY()) && a.getY() < Math.max(m.getY(),n.getY()))
return true;
else
return false;
}
public boolean IsReallyCollinearInclude(Points a){
if(a.getX() >= Math.min(m.getX(),n.getX()) && a.getX() <= Math.max(m.getX(),n.getX()) && a.getY() >= Math.min(m.getY(),n.getY()) && a.getY() <= Math.max(m.getY(),n.getY()))
return true;
else
return false;
}
public boolean IsParallel(Line l){
if( this.slope() == l.slope() ){
return true;
}
else
return false;
}
}
class Points {
private double x;
private double y;
public Points(){
}
public Points(double x,double y){
this.x = x;
this.y = y;
}
public Points(Points a){
this.x = a.getX();
this.y = a.getY();
}
public void setX(double x){
this.x = x;
}
public void setY(double y){
this.y = y;
}
public double getX(){
return this.x;
}
public double getY(){
return this.y;
}
public boolean CheckPoints(Points p){
if( Math.abs(getX() - p.getX() )< 0.001 && Math.abs(getY() - p.getY() )< 0.001){
//System.out.println("points coincide");
return true;
}
else
return false;
}
public double PointsDistance(double x,double y){
return Math.sqrt(Math.pow((x - this.x),2) + Math.pow((y - this.y),2) );
}
}
类图:
SourceMonitor生成的报表内容:
代码分析总结: 第三题由于复杂度比较高,所以代码复杂度也高,没能很好的降低复杂度,减少条件判断,还可对某些复杂度高的方法进行精简。
3. 采坑心得:
前两次作业比较简单,也没踩什么坑,坑主要在第三次作业上。
3-1我的正则表达式之前是单独未考虑0这一情况的,而在之后才单独想起还可能只有一个0的请况。这是改进和的正则表达式:
3-2的坑主要在于与第一题不同,它有一个坐标中包含多个逗号的测试点,如2,1,3对于数字上它是符合格式的,单实际是不符合的,我被卡了很久才想到这种情况,通过一个简单的判断排除,判断如下:
3-3我踩的坑首先是判断顺序的问题case3要先判断直角三角形再去判断钝角和锐角(疑似是有误差比较大的测试点,我被卡了很久)。第二个坑在case4的数据上,由于第三题要求要四舍五入,但计算过程中最好不要,且尽量使计算步骤少,最后再进行四舍五入,不然容易逻辑正确而被数据问题卡住。
4. 改进心得:
1.虽然大部分功能都抽象到了类的方法中,但任有部分重复功能和重复判断未能很好地抽象出去,导致main中复杂度较高。
2.第一次写这种难度的大作业,没养成注释的习惯,导致代码可读性较低,还好取名没随便取,否则难以阅读,需要适当添加注释。
3.对数据的一些四舍五入等不应该放在方法中,应该在需要四舍五入的地方再进行,否则可能导致之后使用方法计算结果对不上。
5. 总结:
通过这几次作业,我初步了解到了面向对象编程的理念以及其优势所在,同时对如何从一个问题中将类和对象抽象出来有了一定的理解。同时也知道了当时老师说的很多类其实现实世界以及分好了,我们直接去用就行了是什么意思。除此之外,也让我对如何检验自己的代码以及如何调试找到错误有了一定的了解。
Ps:数学知识也是真的很重要。😍
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 提示词工程——AI应用必不可少的技术
· 地球OL攻略 —— 某应届生求职总结
· 字符编码:从基础到乱码解决
· SpringCloud带你走进微服务的世界