前言
经过这几周的学习,头发掉了不少。。。。。。
难度是在加大的,尤其是多边形部分的作业,真的很让崩溃,还好没有彻底崩掉。多边形部分测试点比较多,在不考虑坐标方法的情况下需要考虑的特殊情况就会增加很多,导致代码过于冗长。经过数次的挣扎之后,还是选择使用坐标方法来减轻因为特殊情况导致的多边形部分代码的pta报错。
期中的题目较为简单,根据类图来完成即可。
设计与分析:
一、期中测试
-
设计一个类表示平面直角坐标系上的点Point,私有属性分别为横坐标x与纵坐标y,数据类型均为实型数,除构造方法以及属性的getter与setter方法外,定义一个用于显示信息的方法display(),用来输出该坐标点的坐标信息,格式如下:
(x,y)
,数值保留两位小数。为简化题目,其中,坐标点的取值范围设定为(0,200]
。若输入有误,系统则直接输出Wrong Format
-
设计一个类表示平面直角坐标系上的线Line,私有属性除了标识线段两端的点point1、point2外,还有一个字符串类型的color,用于表示该线段的颜色,同样,除构造方法以及属性的getter与setter方法外,定义一个用于计算该线段长度的方法getDistance(),还有一个用于显示信息的方法display(),用来输出线段的相关信息,输出格式如下:
``` The line's color is:颜色值 The line's begin point's Coordinate is: (x1,y1) The line's end point's Coordinate is: (x2,y2) The line's length is:长度值 ```
其中,所有数值均保留两位小数,建议可用
String.format("%.2f", data)
方法。设计类图如下图所示。
** 题目要求:在主方法中定义一条线段对象,从键盘输入该线段的起点坐标与终点坐标以及颜色,然后调用该线段的display()方法进行输出。**
- 以下情况为无效作业
- 无法运行
- 设计不符合所给类图要求
- 未通过任何测试点测试
- 判定为抄袭
输入格式:
分别输入线段的起点横坐标、纵坐标、终点的横坐标、纵坐标以及颜色,中间可用一个或多个空格、tab或者回车分隔。
输出格式:
The line's color is:颜色值
The line's begin point's Coordinate is:
(x1,y1)
The line's end point's Coordinate is:
(x2,y2)
The line's length is:长度值
输入样例1:
在这里给出一组输入。例如:
5
9.4
12.3
84
Red
输出样例1:
在这里给出相应的输出。例如:
The line's color is:Red
The line's begin point's Coordinate is:
(5.00,9.40)
The line's end point's Coordinate is:
(12.30,84.00)
The line's length is:74.96
输入样例2:
在这里给出一组输入。例如:
80.2356
352.12
24.5
100
Black
输出样例2:
在这里给出相应的输出。例如:
Wrong Format
分析:
这道题是很基础的继承类题目,按照给的类图进行编写就可以了,后面的两道题也是根据第一道题来增删查改的。
主要的类代码如下:
point类:
class Point { private double x; private double y; public Point() { } public Point(double x, double y) { super(); this.x = x; this.y = y; } public double getX() { return x; } public void setX(double x) { this.x = x; } public double getY() { return y; } public void setY(double y) { this.y = y; } public void display() { System.out.print("("); System.out.printf("%.2f",this.x); System.out.print(","); System.out.printf("%.2f",this.y); System.out.println(")"); } public static boolean pointPutIsFormatTure(double date) { return date>0&&date<=200; } }
Plane类:
class Plane extends Element{ private String color; Plane() { } Plane(String color) { this.color=color; } String getColor() { return color; } void setColor(String color) { this.color=color; } @Override public void dispiay() { // TODO 自动生成的方法存根 System.out.print("The Plane's color is:"+this.color); } }
分析:
在第一题的基础上,只需要加一个父类,再根类图和要求修改代码,就可以实现了。
public class Main { public static void main(String[] args) { // TODO Auto-generated method stub GeometryObject geo = new GeometryObject(); Scanner in = new Scanner(System.in); while(true) { int choice = in.nextInt(); if(choice==0) { break; } switch(choice) { case 1: double px = in.nextDouble(); double py = in.nextDouble(); if(px<=0||px>200||py<=0||py>200) { System.out.println("Wrong Format"); System.exit(0); } geo.add(new Point(px,py)); break; case 2: double ppx = in.nextDouble(); double ppy = in.nextDouble(); double qx = in.nextDouble(); double qy = in.nextDouble(); String color = in.next(); if(ppx<=0||ppx>200||ppy<=0||ppy>200||qx<=0||qx>200||qy<=0||qy>200) { System.out.println("Wrong Format"); System.exit(0); } Point p = new Point(ppx,ppy); Point q = new Point(qx,qy); Line l = new Line(p,q,color); geo.add(l); break; case 3: String planecolor = in.next(); Plane plane = new Plane(planecolor); geo.add(plane); break; case 4: int choose = in.nextInt(); geo.remove(choose); break; default: break; } } for(Element element : geo.getList()) { element.display(); } } }
圈复杂度分析:
采坑心得:
做完这道题,我才发现细心是多麽重要。我们在写代码时通常习惯将一些相同的代码复制粘贴到某处,这样做固然可以节省时间,但是也要注意变量的名字,我就是因为复制了一个Point1在本应该是写Point2的地方上,结果粗心忘了改过来,结果在运行是Point2老是报错为空,于是我又花了大把时间去debug和肉眼查找,浪费了很多时间,因为这是考试,所以这也影响了之后的心态,仔细是那么重要!。
改进建议:对于自己不太记得的知识点,直接去查询正确的方式减少不必要的时间浪费。
二、凸五边形的计算
用户输入一组选项和数据,进行与五边形有关的计算。
以下五边形顶点的坐标要求按顺序依次输入,连续输入的两个顶点是相邻顶点,第一个和最后一个输入的顶点相邻。
选项包括:
1:输入五个点坐标,判断是否是五边形,判断结果输出true/false。
2:输入五个点坐标,判断是凹五边形(false)还是凸五边形(true),如果是凸五边形,则再输出五边形周长、面积,结果之间以一个英文空格符分隔。 若五个点坐标无法构成五边形,输出"not a pentagon"
3:输入七个点坐标,前两个点构成一条直线,后五个点构成一个凸五边形、凸四边形或凸三角形,输出直线与五边形、四边形或三角形相交的交点数量。如果交点有两个,再按面积从小到大输出被直线分割成两部分的面积(不换行)。若直线与多边形形的一条边线重合,输出"The line is coincide with one of the lines"。若后五个点不符合五边形输入,若前两点重合,输出"points coincide"。
以上3选项中,若输入的点无法构成多边形,则输出"not a polygon"。输入的五个点坐标可能存在冗余,假设多边形一条边上两个端点分别是x、y,边线中间有一点z,另一顶点s:
1)符合要求的输入:顶点重复或者z与xy都相邻,如:x x y s、x z y s、x y x s、s x y y。此时去除冗余点,保留一个x、一个y。
2) 不符合要求的输入:z不与xy都相邻,如:z x y s、x z s y、x s z y
输入格式:
基本格式:选项+":"+坐标x+","+坐标y+" "+坐标x+","+坐标y。点的x、y坐标之间以英文","分隔,点与点之间以一个英文空格分隔。
输出格式:
基本输出格式见每种选项的描述。
异常情况输出:
如果不符合基本格式,输出"Wrong Format"。
如果符合基本格式,但输入点的数量不符合要求,输出"wrong number of points"。
注意:输出的数据若小数点后超过3位,只保留小数点后3位,多余部分采用四舍五入规则进到最低位。小数点后若不足3位,按原始位数显示,不必补齐。例如:1/3的结果按格式输出为 0.333,1.0按格式输出为1.0
输入样例1:
选项1,点重合。例如:
1:-1,-1 1,2 -1,1 1,0
输出样例:
在这里给出相应的输出。例如:
wrong number of points
主类代码:
public class Main{ public static void main(String[] args) { Scanner scanner = new Scanner(System.in); String str = scanner.nextLine(); char []ch=str.toCharArray(); int c=0; //判断输入格式是否正确 if(!str.matches("^[1-5][:](([+-]?(0|(0\\.\\d+)|[1-9][0-9]*(\\.\\d+)?))[,]([+-]?(0|(0\\.\\d+)|[1-9][0-9]*(\\.\\d+)?))\\s?)+$")){ System.out.println("Wrong Format"); return; } //取出cmd,将串转化为浮点型 int cmd = str.charAt(0)-'0'; str = str.substring(2).trim(); String[] tmstr = str.split(" |,"); double[] number = new double[30]; int count = 0; for(String s:tmstr){ if(!check(s)){ System.out.println("wrong number of points"); } number[count++] = Double.parseDouble(s); } //将浮点型转化为坐标点型 Point[] p = new Point[10]; for(int i=0;i<count;i+=2){ p[i/2] = new Point(number[i],number[i+1]); } pointsCntCheck(cmd,count); if(cmd == 1){ try{ Pentagon pentagon = new Pentagon(new Point[]{p[0],p[1],p[2],p[3],p[4]}); System.out.println("true"); }catch (Exception reason){ System.out.println("false"); } } else if(cmd == 2){ try{ Pentagon pentagon = new Pentagon(new Point[]{p[0],p[1],p[2],p[3],p[4]}); if(pentagon.isConvexGraphical){ System.out.printf("%s %s %s\n",pentagon.isConvexGraphical,change(pentagon.sideLength),change(pentagon.area)); } else System.out.println("false"); }catch (Exception reason){ System.out.println(reason.getMessage()); } } else if(cmd == 3){ Line line = null; try{ line = new Line(p[0],p[1]); } catch (Exception reason){ System.out.println(reason.getMessage()); } Graph graphical = new Graph(new Point[]{p[2],p[3],p[4],p[5],p[6]}); if(graphical.status == -1){ System.out.println("not a polygon"); System.exit(0); } if(graphical.len == 5){ try{ Pentagon pentagon = new Pentagon(graphical.points); solve(line,pentagon); }catch (Exception reason){} } if(graphical.len == 4){ try{ Quadrilateral quadrilateral = new Quadrilateral(graphical.points); solve(line,quadrilateral); }catch (Exception reason){} } if(graphical.len == 3){ try{ Triangle triangle = new Triangle(graphical.points); solve(line,triangle); }catch (Exception reason){} } } /*main end*/ } public static void solve(Line line,Pentagon pentagon){ for(Line item:pentagon.lines){ if(line.isSameTo(item)){ System.out.println("The line is coincide with one of the lines"); return; } } Point[] intersections = new Point[5]; for(int i=0;i<5;i++){ intersections[i] = line.getIntersection(pentagon.lines[i]); } boolean[] check = new boolean[]{false,false,false,false,false}; for(int i=0;i<5;i++){ if(intersections[i] != null){ check[i] = intersections[i].inLineSegment(pentagon.lines[i]); } } //以上求出交点,并求出交点是否在边之上 /*特判交点在角上面的情况*/ for(int i=0;i<5;i++){ if(pentagon.points[i].inLine(line)){ //两个不相邻角在line之上 if(pentagon.points[(i+2)%pentagon.len].inLine(line)){ pr_ans(pentagon,pentagon.points[i], pentagon.points[(i+1)%pentagon.len], pentagon.points[(i+2)%pentagon.len]); } else if(pentagon.points[(i+3)%pentagon.len].inLine(line)){ pr_ans(pentagon,pentagon.points[i], pentagon.points[(i+3)%pentagon.len], pentagon.points[(i+4)%pentagon.len]); } //对边和line有交点(分割为两个四边形) else if(check[(i+2)%pentagon.len]){ Graph tmp = new Graph(new Point[]{pentagon.points[i], pentagon.points[(i+1)%pentagon.len], pentagon.points[(i+2)%pentagon.len], intersections[(i+2)%pentagon.len]}); double[] ans = new double[]{tmp.area, pentagon.area - tmp.area}; Arrays.sort(ans); System.out.printf("2 %s %s\n",change(ans[0]),change(ans[1])); } //剩余两个不相邻边和line有交点 else if(check[(i+1)%pentagon.len]){ pr_ans(pentagon,pentagon.points[i], pentagon.points[(i+1)%pentagon.len], intersections[(i+1)%pentagon.len]); } else if(check[(i+3)%pentagon.len]){ pr_ans(pentagon,pentagon.points[i], pentagon.points[(i+4)%pentagon.len], intersections[(i+3)%pentagon.len]); } //就一个交点 else{ System.out.println("1"); } return;//别忘了 } } /*交点分别在边上面的情况*/ for(int i=0;i<5;i++){ if(check[i] && check[(i+2)%pentagon.len]){ Graph tmp = new Graph(new Point[]{intersections[i], pentagon.points[(i+1)%pentagon.len], pentagon.points[(i+2)%pentagon.len], intersections[(i+2)%pentagon.len]}); double[] ans = new double[]{tmp.area, pentagon.area - tmp.area}; Arrays.sort(ans); System.out.printf("2 %s %s\n",change(ans[0]),change(ans[1])); return; } if(check[i] && check[(i+3)%pentagon.len]){ Graph tmp = new Graph(new Point[]{intersections[i], pentagon.points[i], pentagon.points[(i+4)%pentagon.len], intersections[(i+3)%pentagon.len]}); double[] ans = new double[]{tmp.area, pentagon.area - tmp.area}; Arrays.sort(ans); System.out.printf("2 %s %s\n",change(ans[0]),change(ans[1])); return; } } /*无交点*/ System.out.println("0"); } public static void solve(Line line,Quadrilateral q){ //与任意一条边重合 for(Line item: q.lines){ if(line.isSameTo(item)){ System.out.println("The line is coincide with one of the lines"); return; } } Point[] intersections = new Point[4]; for(int i=0;i<4;i++){ intersections[i] = line.getIntersection(q.lines[i]); } boolean[] check = new boolean[]{false,false,false,false}; for(int i=0;i<4;i++){ if(intersections[i] != null){ check[i] = intersections[i].inLineSegment(q.lines[i]); } } //以上求出交点,并求出交点是否在边之上 /*特判交点在角上面的情况*/ for(int i=0;i<4;i++){ if(q.points[i].inLine(line)){ //对角在line之上 if(q.points[(i+2)%q.len].inLine(line)){ pr_ans(q,q.points[i], q.points[(i+1)%q.len], q.points[(i+2)%q.len]); } //两个对边和line有交点 else if(check[(i+1)%q.len]){ pr_ans(q, q.points[i], q.points[(i+1)%q.len], intersections[(i+1)%q.len]); } else if(check[(i+2)%q.len]){ pr_ans(q, q.points[i], q.points[(i+3)%q.len], intersections[(i+2)%q.len]); } //就一个交点 else{ System.out.println("1"); } return;//别忘了 } } /*两组对边和line有交点的情况*/ for(int i=0;i<2;i++){ if(check[i] && check[(i+2)%q.len]){ Graph tmp = new Graph(new Point[]{intersections[i], q.points[(i+1)%q.len], q.points[(i+2)%q.len], intersections[(i+2)%q.len]}); double[] ans = new double[]{tmp.area, q.area - tmp.area}; Arrays.sort(ans); System.out.printf("2 %s %s\n",change(ans[0]),change(ans[1])); return; } } /*无交点*/ System.out.println("0"); } public static void solve(Line line,Triangle triangle){ //与任意一条边重合 if(line.isSameTo(triangle.lines[0]) || line.isSameTo(triangle.lines[1]) || line.isSameTo(triangle.lines[2])){ System.out.println("The line is coincide with one of the lines"); return; } //与三条边的交点(值可能为null,即平行) Point p_ab = line.getIntersection(triangle.lines[0]); Point p_bc = line.getIntersection(triangle.lines[1]); Point p_ca = line.getIntersection(triangle.lines[2]); //三交点是否位于边之内 boolean p_ab_in=false, p_bc_in =false, p_ca_in=false; if(p_ab != null) p_ab_in = p_ab.inLineSegment(triangle.lines[0]); if(p_bc != null) p_bc_in = p_bc.inLineSegment(triangle.lines[1]); if(p_ca != null) p_ca_in = p_ca.inLineSegment(triangle.lines[2]); //任一角在直线之上(特判三角形的角) if(triangle.points[0].inLine(line)){ //与另一条边无交点或者交点在边之外 if(p_ca == null || !p_ca.inLineSegment_close(triangle.lines[2])){ System.out.println("1"); } else pr_ans(triangle,triangle.points[0],triangle.points[1],p_ca); return; } if(triangle.points[1].inLine(line)){ if(p_ca == null || !p_ca.inLineSegment_close(triangle.lines[1])){ System.out.println("1"); } else pr_ans(triangle,triangle.points[0],triangle.points[1],p_ca); return; } if(triangle.points[2].inLine(line)){ if(p_ab == null || !p_ab.inLineSegment_close(triangle.lines[0])){ System.out.println("1"); } else pr_ans(triangle,triangle.points[0],triangle.points[2],p_ab); return; } //两个交点 if(p_ab_in && p_bc_in){ pr_ans(triangle,triangle.points[1],p_ab,p_bc);return;} if(p_bc_in && p_ca_in){ pr_ans(triangle,triangle.points[2],p_bc,p_ca);return;} if(p_ca_in && p_ab_in){ pr_ans(triangle,triangle.points[0],p_ca,p_ab);return;} //无交点 System.out.println("0"); } public static void pr_ans(Triangle t, Point a,Point b,Point c){ double[] ans = new double[2]; ans[0] = Triangle.area(a,b,c); ans[1] = t.area - ans[0]; Arrays.sort(ans); System.out.printf("2 %s %s\n",change(ans[0]),change(ans[1])); } public static void pr_ans(Quadrilateral q,Point a,Point b,Point c){ double[] ans = new double[2]; ans[0] = Triangle.area(a,b,c); ans[1] = q.area - ans[0]; Arrays.sort(ans); System.out.printf("2 %s %s\n",change(ans[0]),change(ans[1])); } public static void pr_ans(Pentagon pentagon,Point a,Point b,Point c){ double[] ans = new double[2]; ans[0] = Triangle.area(a,b,c); ans[1] = pentagon.area - ans[0]; Arrays.sort(ans); System.out.printf("2 %s %s\n",change(ans[0]),change(ans[1])); } public static void pointsCntCheck(int cmd,int cnt){ if(cmd == 1 || cmd == 2){ if(cnt != 10){ System.out.println("wrong number of points"); System.exit(0); } } if(cmd == 3){ if(cnt != 14){ System.out.println("wrong number of points"); System.exit(0); } } } public static boolean check(String str){ return str.matches("^[+-]?(0|(0\\.\\d+)?|[1-9][0-9]*(\\.\\d+)?)$"); } public static String change(double a){ String res = String.format("%.3f",a); res = res.replaceAll("0+?$", ""); if(res.charAt(res.length()-1) == '.') res+='0'; return res; } }
分析:
最开始仍是对输入的字符串进行格式的判断并存储点坐标。判断五边形我用的是连续三点没有形成直线并且对应直线不相交。判断凹凸性我借鉴的网上的方法利用叉乘。周长面积我用了相应的数学方法。
用户输入一组选项和数据,进行与五边形有关的计算。
以下五边形顶点的坐标要求按顺序依次输入,连续输入的两个顶点是相邻顶点,第一个和最后一个输入的顶点相邻。
选项包括:
4:输入十个点坐标,前、后五个点分别构成一个凸多边形(三角形、四边形、五边形),判断它们两个之间是否存在包含关系(一个多边形有一条或多条边与另一个多边形重合,其他部分都包含在另一个多边形内部,也算包含)。
两者存在六种关系:1、分离(完全无重合点) 2、连接(只有一个点或一条边重合) 3、完全重合 4、被包含(前一个多边形在后一个多边形的内部)5、交错 6、包含(后一个多边形在前一个多边形的内部)。
各种关系的输出格式如下:
1、no overlapping area between the previous triangle/quadrilateral/ pentagon and the following triangle/quadrilateral/ pentagon
2、the previous triangle/quadrilateral/ pentagon is connected to the following triangle/quadrilateral/ pentagon
3、the previous triangle/quadrilateral/ pentagon coincides with the following triangle/quadrilateral/ pentagon
4、the previous triangle/quadrilateral/ pentagon is inside the following triangle/quadrilateral/ pentagon
5、the previous triangle/quadrilateral/ pentagon is interlaced with the following triangle/quadrilateral/ pentagon
6、the previous triangle/quadrilateral/ pentagon contains the following triangle/quadrilateral/ pentagon
5:输入十个点坐标,前、后五个点分别构成一个凸多边形(三角形、四边形、五边形),输出两个多边形公共区域的面积。注:只考虑每个多边形被另一个多边形分割成最多两个部分的情况,不考虑一个多边形将另一个分割成超过两个区域的情况。
6:输入六个点坐标,输出第一个是否在后五个点所构成的多边形(限定为凸多边形,不考虑凹多边形),的内部(若是五边形输出in the pentagon/outof the pentagon,若是四边形输出in the quadrilateral/outof the quadrilateral,若是三角形输出in the triangle/outof the triangle)。输入入错存在冗余点要排除,冗余点的判定方法见选项5。如果点在多边形的某条边上,输出"on the triangle/on the quadrilateral/on the pentagon"。
以上4、5、6选项输入的五个点坐标可能存在冗余,假设多边形一条边上两个端点分别是x、y,边线中间有一点z,另一顶点s:
1)符合要求的输入:顶点重复或者z与xy都相邻,如:x x y s、x z y s、x y x s、s x y y。此时去除冗余点,保留一个x、一个y。
2) 不符合要求的输入:z不与xy都相邻,如:z x y s、x z s y、x s z y
输入格式:
基本格式:选项+":"+坐标x+","+坐标y+" "+坐标x+","+坐标y。点的x、y坐标之间以英文","分隔,点与点之间以一个英文空格分隔。
输出格式:
输出的数据若小数点后超过3位,只保留小数点后3位,多余部分采用四舍五入规则进到最低位。小数点后若不足3位,按原始位数显示,不必补齐。例如:1/3的结果按格式输出为 0.333,1.0按格式输出为1.0
输入样例:
在这里给出一组输入。例如:
4:0,0 6,0 7,1 8,3 6,6 0,0 6,0 7,1 8,3 6,6
输出样例:
在这里给出相应的输出。例如:
the previous pentagon coincides with the following pentag
主类代码:
public class Main { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); String str = scanner.nextLine(); char[] ch = str.toCharArray(); int c = 0; //判断输入格式是否正确 if (!str.matches("^[1-9][:](([+-]?(0|(0\\.\\d+)|[1-9][0-9]*(\\.\\d+)?))[,]([+-]?(0|(0\\.\\d+)|[1-9][0-9]*(\\.\\d+)?))\\s?)+$")) { System.out.print("Wrong Format"); System.exit(0); } for (int i = 0; i < str.length(); i++) { if (ch[i] == ',') c++; } /* if (c != 5) { System.out.print("wrong number of points"); System.exit(0); } */ String []a= str.split(" |,|:"); String a1=a[0]; String b1=a[1]; String a2=a[2]; String b2=a[3]; String a3=a[4]; String b3=a[5]; String a4=a[6]; String b4=a[7]; String a5=a[8]; String b5=a[9]; double x1=Double.parseDouble(a1); double y1=Double.parseDouble(b1); double x2=Double.parseDouble(a2); double y2=Double.parseDouble(b2); double x3=Double.parseDouble(a3); double y3=Double.parseDouble(b3); double x4=Double.parseDouble(a4); double y4=Double.parseDouble(b4); double x5=Double.parseDouble(a5); double y5=Double.parseDouble(b5); if(ch[0]==1){ wbx1 w=new wbx1(); double wb1=w.zx(x1,y1,x2,y2,x3,y3); double wb2=w.zx(x1,y1,x2,y2,x4,y4); double wb3=w.zx(x1,y1,x2,y2,x5,y5); double wb4=w.zx(x2,y2,x3,y3,x4,y4); double wb5=w.zx(x2,y2,x3,y3,x5,y5); double wb6=w.zx(x3,y3,x4,y4,x5,y5); double wb7=w.zx(x1,y1,x4,y4,x5,y5); double wb8=w.zx(x1,y1,x3,y3,x4,y4); double wb9=w.zx(x1,y1,x3,y3,x5,y5); double wb10=w.zx(x2,y2,x4,y4,x5,y5); if(wb1==0&&wb2==0&&wb3==0&&wb4==0&&wb5==0&&wb6==0&&wb7==0&&wb8==0&&wb9==0&&wb9==0){ System.out.print("false"); } } //取出cmd,将串转化为浮点型 int cmd = str.charAt(0) - '0'; str = str.substring(2).trim(); String[] tmpstr = str.split(" |,"); double[] num = new double[30]; int count = 0; for (String s : tmpstr) { if (!check(s)) { System.out.println("wrong number of points"); System.exit(0); } num[count++] = Double.parseDouble(s); } //将浮点型转化为坐标点型 Point[] p = new Point[10]; for (int i = 0; i < count; i += 2) { p[i / 2] = new Point(num[i], num[i + 1]); } pointsCntCheck(cmd, count); switch (cmd){ case 4: if (cmd == 4) { Graphical graphical1 = new Graphical(new Point[]{p[0], p[1], p[2], p[3], p[4]}); Graphical graphical2 = new Graphical(new Point[]{p[5], p[6], p[7], p[8], p[9]}); System.out.println(graphical1.relationshipWith(graphical2)); } case 5: if (cmd == 5) { Graphical graphical1 = new Graphical(new Point[]{p[0], p[1], p[2], p[3], p[4]}); Graphical graphical2 = new Graphical(new Point[]{p[5], p[6], p[7], p[8], p[9]}); System.out.println(change(graphical1.overlappingArea(graphical2))); } case 6: if (cmd == 6) { Graphical graphical1 = new Graphical(new Point[]{p[1], p[2], p[3], p[4], p[5]}); int res = graphical1.isContainPoint(p[0]); String[] name = new String[]{"triangle", "quadrilateral", "pentagon"}; if (res == -1) { System.out.println("in the " + name[graphical1.len - 3]); System.out.print(""); } if (res == 0) { System.out.println("on the " + name[graphical1.len - 3]); System.out.print(""); } if (res == 1) { System.out.println("outof the " + name[graphical1.len - 3]); System.out.print(""); } } default: break; } } public static void pointsCntCheck(int cmd,int cnt){ if(cmd == 4 || cmd == 5){ if(cnt != 20){ System.out.println("wrong number of points"); System.out.print(""); return; } } if(cmd == 6){ if(cnt != 12){ System.out.println("wrong number of points"); System.exit(0); } } } public static String change(double a){ String res = String.format("%.3f",a); res = res.replaceAll("0+?$", ""); if(res.charAt(res.length()-1) == '.') res+='0'; return res; } public static boolean check(String str){ return str.matches("^[+-]?(0|(0\\.\\d+)?|[1-9][0-9]*(\\.\\d+)?)$"); } }
分析:
最开始仍是对输入的字符串进行格式的判断并存储点坐标。判断五边形我用的是连续三点没有形成直线并且对应直线不相交。周长面积我用了相应的数学方法。
圈复杂的分析:
踩坑心得:在写最后一点的时候,一直运行不出自己想要的结果,并且自己用的一些方法也是之前的一些功能里用过的,调试检查了半天,才发现是自己传入的参数传错了。
三、凸四边形
用户输入一组选项和数据,进行与四边形有关的计算。
以下四边形顶点的坐标要求按顺序依次输入,连续输入的两个顶点是相邻顶点,第一个和最后一个输入的顶点相邻。
选项包括:
1:输入四个点坐标,判断是否是四边形、平行四边形,判断结果输出true/false,结果之间以一个英文空格符分隔。
2:输入四个点坐标,判断是否是菱形、矩形、正方形,判断结果输出true/false,结果之间以一个英文空格符分隔。 若四个点坐标无法构成四边形,输出"not a quadrilateral"
3:输入四个点坐标,判断是凹四边形(false)还是凸四边形(true),输出四边形周长、面积,结果之间以一个英文空格符分隔。 若四个点坐标无法构成四边形,输出"not a quadrilateral"
4:输入六个点坐标,前两个点构成一条直线,后四个点构成一个四边形或三角形,输出直线与四边形(也可能是三角形)相交的交点数量。如果交点有两个,再按面积从小到大输出四边形(或三角形)被直线分割成两部分的面积(不换行)。若直线与四边形或三角形的一条边线重合,输出"The line is coincide with one of the lines"。若后四个点不符合四边形或三角形的输入,输出"not a quadrilateral or triangle"。
后四个点构成三角形的情况:假设三角形一条边上两个端点分别是x、y,边线中间有一点z,另一顶点s:
1)符合要求的输入:顶点重复或者z与xy都相邻,如x x y s、x z y s、x y x s、s x y y。此时去除冗余点,保留一个x、一个y。
2) 不符合要求的输入:z 不与xy都相邻,如z x y s、x z s y、x s z y
5:输入五个点坐标,输出第一个是否在后四个点所构成的四边形(限定为凸四边形,不考虑凹四边形)或三角形(判定方法见选项4)的内部(若是四边形输出in the quadrilateral/outof the quadrilateral,若是三角形输出in the triangle/outof the triangle)。如果点在多边形的某条边上,输出"on the triangle或者on the quadrilateral"。若后四个点不符合四边形或三角形,输出"not a quadrilateral or triangle"。
输入格式:
基本格式:选项+":"+坐标x+","+坐标y+" "+坐标x+","+坐标y。点的x、y坐标之间以英文","分隔,点与点之间以一个英文空格分隔。
输出格式:
基本输出格式见每种选项的描述。
异常情况输出:
如果不符合基本格式,输出"Wrong Format"。
如果符合基本格式,但输入点的数量不符合要求,输出"wrong number of points"。
注意:输出的数据若小数点后超过3位,只保留小数点后3位,多余部分采用四舍五入规则进到最低位。小数点后若不足3位,按原始位数显示,不必补齐。例如:1/3的结果按格式输出为 0.333,1.0按格式输出为1.0
选项1、2、3中,若四边形四个点中有重合点,输出"points coincide"。
选项4中,若前两个输入线的点重合,输出"points coincide"。
输入样例1:
选项1,点重合。例如:
1:-1,-1 -1,-1 1,2 1,-2
输出样例:
在这里给出相应的输出。例如:
points coincide
输入样例2:
不符合基本格式。例如:
1:-1,-1 1,2 -1,1 ++1,0
输出样例:
在这里给出相应的输出。例如:
Wrong Format
输入样例3:
选项1,输入点数量不对。例如:
1:-1,-1 -1,2
输出样例:
在这里给出相应的输出。例如:
wrong number of points
输入样例4:
选项1,正确输入判断。例如:
1:-1,-1 -1,1 1,2 1,-2
输出样例:
在这里给出相应的输出。例如:
true false
输入样例5:
选项2,输入点不构成四边形。例如:
2:10,10 1,1 0,0 1,20
输出样例:
在这里给出相应的输出。例如:
not a quadrilateral
输入样例6:
选项2,正方形。例如:
2:0,0 0,80 80,80 80,0
输出样例:
在这里给出相应的输出。例如:
true true true
输入样例7:
选项2。例如:
2:0,0 -10,80 0,160 -10,80
输出样例:
在这里给出相应的输出。例如:
not a quadrilateral
输入样例8:
选项3,凸四边形。例如:
3:-1,-1 -1,1 1,2 1,-2
输出样例:
在这里给出相应的输出。例如:
true 10.472 6.0
输入样例9:
选项3,。例如:
3:0,0 -10,100 0,99 10,100
输出样例:
在这里给出相应的输出。例如:
false 221.097 990.0
类图:
分析:我首先都是对输入的字符串进行格式的判断,再进入相应的函数去操作。四边形判断是通过判断是否有连续三点共线。周长面积是通过相应的数学计算来计算。
主类代码:
public class Main { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); String st = scanner.nextLine(); if(!st.matches("^[1-5][:](([+-]?(0|(0\\.\\d+)|[1-9][0-9]*(\\.\\d+)?))[,]([+-]?(0|(0\\.\\d+)|[1-9][0-9]*(\\.\\d+)?))\\s?)+$")){ System.out.println("Wrong Format"); System.out.print(""); System.exit(0); } int cm = st.charAt(0)-'0'; st = st.substring(2).trim(); String[] tmp = st.split(" |,"); double[] number = new double[40]; int count = 0; for(String sel:tmp){ if(!check(sel)){ System.out.println("Wrong Format"); System.out.printf(""); System.exit(0); } number[count++] = Double.parseDouble(sel); } //将浮点型转化为坐标点型 Point[] p = new Point[10]; for(int i=0;i<count;i+=2){ p[i/2] = new Point(number[i],number[i+1]); } //点数不合法 if(cm==1 || cm==2 || cm==3){ if(count != 8){ System.out.println("wrong number of points"); System.out.printf(""); return; } } if(cm==4){ if(count != 12){ System.out.println("wrong number of points"); System.out.print(""); return; } } if(cm == 5){ if(count != 10){ System.out.println("wrong number of points"); System.out.print(""); return; } } if(cm == 1){ try{ Quadrilateral q = new Quadrilateral(p[0],p[1],p[2],p[3]); System.out.printf("true %s\n",q.isParallelQuadrilateral()); System.out.print(""); }catch (Exception e){ if(e.getMessage().equals("not a quadrilateral")) System.out.println("false false"); else System.out.println(e.getMessage()); } } if(cm == 2){ try{ Quadrilateral q = new Quadrilateral(p[0],p[1],p[2],p[3]); System.out.printf("%s %s %s\n",q.isDiamond(),q.isRectangle(),q.isSquare()); } catch (Exception e){ System.out.println("not a quadrilateral"); System.out.print(""); } } if(cm == 3){ try{ Quadrilateral q = new Quadrilateral(p[0],p[1],p[2],p[3]); System.out.printf("%s %s %s\n",q.isConvexQuadrilateral(),change(q.sideLength()), change(q.area()) ); }catch (Exception e){ System.out.println(e.getMessage()); System.out.printf(""); } } if(cm == 4){ Line le = null; Quadrilateral q = null; try{ le = new Line(p[0],p[1]); }catch (Exception e){ //不构成直线 System.out.println(e.getMessage()); System.exit(0); } try{ //构成四边形(执行有关四边形的计算) q = new Quadrilateral(p[2],p[3],p[4],p[5]); solve(le,q); return; }catch (Exception e){ //可能构成三角形 try{ //保证以下代码正确,捕获异常并吞并 //以5号点作为s顶点 if(!p[2].isSameTo(p[4])){ //2,4点不重合 Line ll = new Line(p[2],p[4]); //3在ll之上,5在ll之外 if(p[3].inLineSegment_close(ll) && !p[5].inLineSegment_close(ll)){ Triangle t = new Triangle(p[2],p[4],p[5]); solve(le,t); return; } } else{ //2,4点重合 if(!p[2].isSameTo(p[3])){ //但是2,3点不重合 Line lll = new Line(p[2],p[3]); if(!p[5].inLineSegment_close(lll)){ //5点在ll线之外 Triangle te = new Triangle(p[2],p[3],p[5]); solve(le,te); return; } } } //以2号点作为顶点 if(!p[3].isSameTo(p[5])){ Line lll = new Line(p[3],p[5]); if(p[4].inLineSegment_close(lll) && !p[2].inLine(lll)){ Triangle te = new Triangle(p[2],p[3],p[5]); solve(le,te); return; } } else{ if(!p[3].isSameTo(p[4])){ Line lll = new Line(p[3],p[4]); if(!p[2].inLineSegment_close(lll)){ Triangle te = new Triangle(p[2],p[3],p[4]); solve(le,te); return; } } } //以4号点作为顶点 if(!p[3].isSameTo(p[5])){ Line lll = new Line(p[3],p[5]); if(p[2].inLineSegment_close(lll) && !p[4].inLine(lll)){ Triangle te = new Triangle(p[3],p[4],p[5]); solve(le,te); return; } } //以3号点作为顶点 if(!p[2].isSameTo(p[4])){ Line lll = new Line(p[2],p[4]); if(p[5].inLineSegment_close(lll) && !p[3].inLine(lll)){ Triangle te = new Triangle(p[2],p[3],p[4]); solve(le,te); return; } } //不构成三角形 System.out.println("not a quadrilateral or triangle"); }catch(Exception ee){} } } if(cm == 5){ try{ //四点构成四边形 Quadrilateral q = new Quadrilateral(p[1],p[2],p[3],p[4]); int op = q.isContainPoint(p[0]); if(op == 0) System.out.println("in the quadrilateral"); else if(op == 1) System.out.println("on the quadrilateral"); else System.out.println("outof the quadrilateral"); }catch(Exception e){ //不构成四边形,待确定是否构成三角形 try{ //保证以下代码正确,捕获异常并吞并 //以4号点作为s顶点 if(!p[1].isSameTo(p[3])){ //1,3点不重合 Line ll = new Line(p[1],p[3]); //2在ll之上,4在ll之外 if(p[2].inLineSegment_close(ll) && !p[4].inLineSegment_close(ll)){ Triangle t = new Triangle(p[1],p[3],p[4]); inTriangle(p[0],t); return; } } else{ //1,3点重合 if(!p[1].isSameTo(p[2])){ //但是2,3点不重合 Line ll = new Line(p[1],p[2]); if(!p[4].inLineSegment_close(ll)){ //5点在ll线之外 Triangle t = new Triangle(p[1],p[2],p[4]); inTriangle(p[0],t); return; } } } //以1号点作为顶点 if(!p[2].isSameTo(p[4])){ Line ll = new Line(p[2],p[4]); if(p[3].inLineSegment_close(ll) && !p[1].inLine(ll)){ Triangle t = new Triangle(p[1],p[2],p[4]); inTriangle(p[0],t); return; } } else{ if(!p[2].isSameTo(p[3])){ Line ll = new Line(p[2],p[3]); if(!p[1].inLineSegment_close(ll)){ Triangle t = new Triangle(p[1],p[2],p[3]); inTriangle(p[0],t); return; } } } //以3号点作为顶点 if(!p[2].isSameTo(p[4])){ Line ll = new Line(p[2],p[4]); if(p[1].inLineSegment_close(ll) && !p[3].inLine(ll)){ Triangle t = new Triangle(p[2],p[3],p[4]); inTriangle(p[0],t); return; } } //以2号点作为顶点 if(!p[1].isSameTo(p[3])){ Line ll = new Line(p[1],p[3]); if(p[4].inLineSegment_close(ll) && !p[2].inLine(ll)){ Triangle t = new Triangle(p[1],p[2],p[3]); inTriangle(p[0],t); return; } } //不构成三角形 System.out.println("not a quadrilateral or triangle"); }catch(Exception ee){} } } } public static boolean check(String str){ return str.matches("^[+-]?(0|(0\\.\\d+)?|[1-9][0-9]*(\\.\\d+)?)$"); } public static void pr_ans(Triangle t, Point a,Point b,Point c){ double[] ansel = new double[2]; ansel[0] = Triangle.area(a,b,c); ansel[1] = t.area() - ansel[0]; Arrays.sort(ansel); System.out.printf("2 %s %s\n",change(ansel[0]),change(ansel[1])); } public static void pr_ans(Quadrilateral q,Point a,Point b,Point c){ double[] ansel = new double[2]; ansel[0] = Triangle.area(a,b,c); ansel[1] = q.area() - ansel[0]; Arrays.sort(ansel); System.out.printf("2 %s %s\n",change(ansel[0]),change(ansel[1])); } public static String change(double a){ String result = String.format("%.3f",a); result = result.replaceAll("0+?$", ""); if(result.charAt(result.length()-1) == '.') result=result+'0'; return result; } //三角形交点情况,上次练习题copy public static void solve(Line li,Triangle tr){ //与任意一条边重合 if(li.isSameTo(tr.ab) || li.isSameTo(tr.ac) || li.isSameTo(tr.bc)){ System.out.println("The line is coincide with one of the lines"); System.out.print(""); return; } //与三条边的交点(值可能为null,即平行) Point p_ab = li.getIntersection(tr.ab); Point p_ac = li.getIntersection(tr.ac); Point p_bc = li.getIntersection(tr.bc); //三交点是否位于边之内 boolean p_ab_in=false, p_ac_in =false, p_bc_in=false; if(p_ab != null) p_ab_in = p_ab.inLineSegment(tr.ab); if(p_ac != null) p_ac_in = p_ac.inLineSegment(tr.ac); if(p_bc != null) p_bc_in = p_bc.inLineSegment(tr.bc); //任一角在直线之上(特判三角形的角) if(tr.a.inLine(li)){ //与另一条边无交点或者交点在边之外 if(p_bc == null || !p_bc.inLineSegment_close(tr.bc)){ System.out.println("1"); } else pr_ans(tr,tr.a,tr.b,p_bc); return; } if(tr.b.inLine(li)){ if(p_ac == null || !p_ac.inLineSegment_close(tr.ac)){ System.out.println("1"); } else pr_ans(tr,tr.a,tr.b,p_ac); return; } if(tr.c.inLine(li)){ if(p_ab == null || !p_ab.inLineSegment_close(tr.ab)){ System.out.println("1"); } else pr_ans(tr,tr.a,tr.c,p_ab); return; } //两个交点 if(p_ab_in && p_bc_in){ pr_ans(tr,tr.b,p_ab,p_bc);return;} if(p_ab_in && p_ac_in){ pr_ans(tr,tr.a,p_ab,p_ac);return;} if(p_bc_in && p_ac_in){ pr_ans(tr,tr.c,p_bc,p_ac);return;} //无交点 System.out.println("0"); } //四边形交点情况 public static void solve(Line l,Quadrilateral q){ //与任意一条边重合 for(Line ll: q.lin){ if(l.isSameTo(ll)){ System.out.println("The line is coincide with one of the lines"); return; } } //与四条边的交点,可能为null; Point p0 = l.getIntersection(q.lin[0]); Point p1 = l.getIntersection(q.lin[1]); Point p2 = l.getIntersection(q.lin[2]); Point p3 = l.getIntersection(q.lin[3]); //判断交点是否在边之上 boolean p0_in = false,p1_in = false,p2_in = false,p3_in = false; if(p0 != null) p0_in = p0.inLineSegment(q.lin[0]); if(p1 != null) p1_in = p1.inLineSegment(q.lin[1]); if(p2 != null) p2_in = p2.inLineSegment(q.lin[2]); if(p3 != null) p3_in = p3.inLineSegment(q.lin[3]); //任一角在直线l之上 if(q.poin[0].inLine(l)){ //它的对角也在边之上 if(q.poin[2].inLine(l)){ pr_ans(q,q.poin[0],q.poin[1],q.poin[2]); } //对角的邻边任一与直线有交点 else if (p2_in){ //邻边之一 pr_ans(q,q.poin[0],p2,q.poin[3]); } else if (p1_in){ //邻边之二 pr_ans(q,q.poin[0],p1,q.poin[1]); } else{ System.out.println("1"); } return; } else if(q.poin[1].inLine(l)){ //它的对角也在边之上 if(q.poin[3].inLine(l)){ pr_ans(q,q.poin[1],q.poin[2],q.poin[3]); } //对角的邻边任一与直线有交点 else if (p2_in){ //邻边之一 pr_ans(q,q.poin[1],p2,q.poin[2]); } else if (p3_in){ //邻边之二 pr_ans(q,q.poin[1],p3,q.poin[0]); } else{ System.out.println("1"); } return; } else if (q.poin[2].inLine(l)) { //它的对角也在边之上 if(q.poin[0].inLine(l)){ pr_ans(q,q.poin[2],q.poin[3],q.poin[0]); } //对角的邻边任一与直线有交点 else if (p3_in){ //邻边之一 pr_ans(q,q.poin[2],p3,q.poin[3]); } else if (p0_in){ //邻边之二 pr_ans(q,q.poin[2],p0,q.poin[1]); } else{ System.out.println("1"); } return; } else if (q.poin[3].inLine(l)) { //它的对角也在边之上 if(q.poin[1].inLine(l)){ pr_ans(q,q.poin[3],q.poin[0],q.poin[1]); } //对角的邻边任一与直线有交点 else if (p0_in){ //邻边之一 pr_ans(q,q.poin[3],p0,q.poin[0]); } else if (p1_in){ //邻边之二 pr_ans(q,q.poin[3],p1,q.poin[2]); } else{ System.out.println("1"); } return; } //两个交点(邻边) if(p0_in && p1_in){pr_ans(q,p0,p1,q.poin[1]);return;} if(p1_in && p2_in){pr_ans(q,p1,p2,q.poin[2]);return;} if(p2_in && p3_in){pr_ans(q,p2,p3,q.poin[3]);return;} if(p3_in && p0_in){pr_ans(q,p3,p0,q.poin[0]);return;} //对边 if(p0_in && p2_in){ double[] ans = new double[2]; ans[0] = Triangle.area(q.poin[0],p0,p2) + Triangle.area(p0,p2,q.poin[3]); ans[1] = Triangle.area(q.poin[1],p0,p2) + Triangle.area(p0,p2,q.poin[2]); Arrays.sort(ans); System.out.printf("2 %s %s\n",change(ans[0]),change(ans[1])); return; } if(p1_in && p3_in){ double[] ans = new double[2]; ans[0] = Triangle.area(q.poin[1],p1,p3) + Triangle.area(p1,p3,q.poin[0]); ans[1] = Triangle.area(q.poin[2],p1,p3) + Triangle.area(p1,p3,q.poin[3]); Arrays.sort(ans); System.out.printf("2 %s %s\n",change(ans[0]),change(ans[1])); return; } //0交点 System.out.println("0"); } //判断点在三角形哪里 public static void inTriangle(Point p,Triangle t){ int op = t.isContainPoint(p); if(op == 0) System.out.println("in the triangle"); else if (op == 1) System.out.println("on the triangle"); else System.out.println("outof the triangle"); } }
圈复杂度分析:
采坑心得:这道题算不上有什么坑踩,主要是自己最开始的设计方法比较繁琐,导致浪费很多时间。在经过和同学的讨论之后,改进了方法让整个代码看起来更加简洁。
改进建议:平时还是要多花时间去研究算法与技巧,不能过于急功近利,导致学到的知识一星半点的。要多去网上查询并且借鉴,学习一些大神的方法。
总结
经过这段时间的学习,我觉得我的代码能力有明显的提升,我对于类的设计更加合理了。在许多时候也能合理运用继承与多态了。还更加了解了泛型容器的使用规则和一些方法。这次最大的收获就是运用的图像Path类方面的特性与方法,这对于图形方面很多问题的解决都提供了很棒的方法。但自己还是太过于懒惰了,没有花太多的时间在java方面的练习与学习。在敲代码时,非常的不熟练,平时没有花时间去练习训练,经常会走弯路进而浪费很多的时间。很少去认真的学习一些算法与技巧。当然有些地方也有些不足,同时自我学习能力也在学习的过程中加强,因为很多东西都是从网络上学习的,在未来的日子里我也要更加努力学习。希望在未来的学习中,我能够熟练地掌握java,能够独立自主的完成一些较复杂的程序编写。通过更多的练习来提高自己的编程能力。将上课所学到的知识运用为自己实践练习的最佳工具。