前言:
(1) 第七次题集只有一道题目——家居强电电路模拟程序-3,这是第三次迭代,这次迭代主要的点有四个。
首先本次迭代添加了线路中存在多个串联起来的并联电路。不同于上次的单并联,本次更复杂。
然后本次还新迭代了一种控制器——互斥开关,互斥开关一共有三个触脚,默认状态是1,2相连,但是互斥开关可以反接所以互斥开关还需要考虑接入的方向,这显然需要需要引入一个新的变量进行判定。然后就是这个互斥开关是有电阻的,并不是理想开关,所以对于短路的判断需要重新考虑。
再然后是串联中包含串联电路,不论是主路还是支路都有可能出现串联电路,这一点还是比较好处理的,本身就是将串联电路设定为了电路设备。
最后是引入了一种受控电器——受控窗帘,收到电压和室内亮度的控制,默认状态为全开。
总体而言本次题解较上次迭代而言难度增幅不算太大。
(2) 第八次题集同样只有一道题目——家居强电电路模拟程序-4,这是本系列题目的第四次迭代,这次迭代引入了很多新的功能,主要有五点。
首先是增加管脚电压的显示,在输出每个电器的状态信息后,再依次输出该电器每个管脚的电压。这一点是最让人头疼的地方,需要好好回忆一下高中的电路,同时有几种特殊情况需要注意情况,不然很容易错。
然后是电流限制,电器在工作时,过大的电流会引起电器过热,从而烧坏电路。本次迭代,每个元器件都有最大电流的设置,当实时电流超过最大电流时,在该电器输出信息的最后加入提示“exceeding current limit error”,与前面的信息之间用英文空格分隔。
再次是短路检测,如果电路出现无穷大的电流造成短路,所有元器件信息不输出,仅输出提示“short circuit error”。
再然后是并联电路中包含并联,本次迭代考虑并联电路中包含并联电路的情况,即构成并联电路的串联电路可以包含别的并联电路。这一点比较好处理,因为并联电路本身也别看作一个电路设备,在支路的输入时,加入这种情况就行。
最后是二极管,增加二极管元件,其电路特性为:正向导通,反向截止;其电器符号如图4所示,当电流从左至右流过时,二极管导通”conduction”,电阻为0;电流从右至左流动时,二极管截止”cutoff”,电阻无穷大,相当于开关打开。
总体而言,本次迭代的难度增加了很多,让人眼前一黑,主要是管脚电压的显示,确实需要考虑很多情况。
第七次题集
设计与分析:
首先本次迭代比起上次需要将串联电路也设置为一个电路设备类,以下是一个简易类图:
对串联类同时也加入了很多新的方法,以下是部分代码展示:
class Series extends Equipment{public double getVoltage() {return voltage;}public void setVoltage(double voltage) {this.voltage = voltage;}private double voltage;public String getName() {return name;}public void setName(String name) {this.name = name;}private String name;public void VoltageDivision(){double aver=getVoltage()/getResistor();for(int i=0;i<list.size();i++){Equipment e= list.get(i);if(e instanceof Switch || e instanceof Governor || e instanceof ContinueGovernor||e instanceof Hswitch)continue;else if(e instanceof Series){e.setVoltage(aver*e.getResistor());e.VoltageDivision();}else{e.setVoltage(aver*e.getResistor());}}}private double resistor;public double getResistor() {resistor = 0;for (int i = 0; i < list.size(); i++) {Equipment e = list.get(i);if (e instanceof Switch || e instanceof Governor || e instanceof ContinueGovernor)continue;else if(e instanceof Hswitch&&e.IfHswitchPath(this.name)){resistor+=e.getResistor();}else{resistor += e.getResistor();}}return resistor;}public boolean IfPathway(){for(int i=0;i< list.size();i++){Equipment e= list.get(i);if(e instanceof Switch){if(e.switchstyle==0){return false;}}else if(e instanceof Parallel&&e.IfPathway()==false){return false;}else if(e instanceof Hswitch&&e.IfHswitchPath(this.name)==false){return false;}else if(e instanceof Series&&!e.IfPathway()){return false;}}return true;}public boolean Ifshort()//检查是否短路 短路就是true 不短路就是false{boolean flag=true;for(int i=0;i<list.size();i++){Equipment e= list.get(i);if(e instanceof Switch&&e.switchstyle==1){continue;}else if(e instanceof Series&& e.Ifshort()){continue;}else{flag=false;break;}}return flag;}public ArrayList<Equipment> getList() {return list;}public void setList(ArrayList<Equipment> list) {this.list = list;}private ArrayList<Equipment> list;Series() {list = new ArrayList<>();}public void addEquipment(Equipment e) {list.add(e);}public Equipment getEquipment(int idex) {return list.get(idex - 1);}}
在串联电路类中对短路和断路的判定方法改了,如果遇见了串联电路,则再次调用该方法,然后就是setVoltage()方法这是负责分压的方法,遇见串联电路时,和遇见其他受控设备一样分压,但是要多加一点,那就是再次分压。
然后就是本次新迭代的受控设备——互斥开关,这个在输入时就需要十分注意它的方向,以下是部分代码:
class Hswitch extends Equipment implements Comparable<Hswitch>{Hswitch(String name){this.name=name;}public void setHchoice(int hchoice){if(hchoice%2==0){Hchoice=2;}elseHchoice=3;}private int Hchoice;String H2;public void setH2(String tname){H2=tname;}String H3;public void setH3(String tname){H3=tname;}@Overridedouble getResistor() {if(Hchoice==2)return 5;elsereturn 10;}@Overridepublic boolean IfHswitchPath(String tname){if(Hchoice==2&&H2!=null&&H2.equals(tname)){return true;}else if(Hchoice==3&&H3!=null&&H3.equals(tname)){return true;}elsereturn false;}@Overridevoid display() {if(Hchoice==2){System.out.println("@"+name+":closed");}elseSystem.out.println("@"+name+":turned on");}@Overridepublic int compareTo(Hswitch o) {if(this.name.compareTo(o.getName())<0)return -1;elsereturn 1;}
}
互斥开关中有一个特殊的布尔变量Hchoice,专门判断互斥开关的触脚1与那个触脚相连,
其中的IfHswitchPath()方法用于判断某条路这个互斥开关是否接通,主要用于判断某条串联是否断路。
互斥开关中也实现了Comparable这个接口,在输出是需要进行排序。
最后是本次迭代的一个新的受控设备——受控窗帘,它只受电压和室内光线的控制,所以判断窗帘的打开程度需要最后判断,在所有分压完成后,以下是部分代码:
class Curtains extends Equipment implements Comparable<Curtains>{private int sumlux;Curtains(String name){this.name=name;}@Overridepublic void setVoltage(double c) {voltage=c;}public void setSumlux(int sumlux){this.sumlux=sumlux;}@Overridedouble getResistor() {return 15;}@Overridevoid display() {if(voltage<50||sumlux<50){System.out.println("@"+name+":100%");}else if(sumlux>=50&&sumlux<100){System.out.println("@"+name+":80%");}else if(sumlux>=100&&sumlux<200){System.out.println("@"+name+":60%");}else if(sumlux>=200&&sumlux<300){System.out.println("@"+name+":40%");}else if(sumlux>=300&&sumlux<400){System.out.println("@"+name+":20%");}else if(sumlux>=400){System.out.println("@"+name+":0%");}}@Overridevoid close() {voltage=0;}@Overridepublic int compareTo(Curtains o) {if(this.name.compareTo(o.getName())<0)return -1;elsereturn 1;}
}
其中的sumlux就是所以灯泡的光亮总和,然后和电压一起判定就行了,这是一个比较简单地受控设备,
同时也同其他设备一样,需要实现Comparable接口,从而重写compareTo方法,便于在最后输出之前进行排序。
踩坑心得:
(1) 开关的闭合情况我没有正确判断,我之前是根据字符串方法contain()方法进行判断是否改变情况,而我对于输入信息中的调节开关的信息没有进行字符串的抓取,就导致一些判断错误。
例如:开关K11,遇见判断信息#K112也会进行调节,可是这两个开关并不是一个,导致答案错误。
例如输入:
#T1:[IN K12-1] [K12-2 D2-1] [D2-2 OUT]
#T2:[IN K123-1] [K123-2 D1-1] [D1-2 OUT]
#T3:[VCC K1-1] [K1-2 T1-IN] [T1-OUT T2-IN] [T2-OUT GND]
#K1
#K12
#K123
end
就会造成错误输出:
@K1:turned on
@K12:closed
@K123:closed
@D1:0
@D2:0
因此在输入开关的判断信息是就需要进行字符串的抓取,
就像下面这样:
if(Line.contains("#K")){String regstr="#(K[0-9]+)";Pattern pattern=Pattern.compile(regstr);Matcher matcher= pattern.matcher(Line);String name="";if(matcher.find()){name=matcher.group(1);}changNumList.add(name);}
这样在比较的时候用equal()方法就不会造成错误。
(2) 然后是一个非常非常非常非常不该出现的错误,可是我又错了,我由于有一个双层循环,内层循环数和外层的循环数写反了,导致有时候会出现null的引用,我一直以为是正则表达式出现了错误,找了很久很久才发现,是我写反了,浪费了大量时间。
这件事告诉我们写代码一定要耐心和细心,不然一步错,想要回头找出来是很艰难的过程,也很痛苦。
改进建议:
(1)代码结构优化:
- 重构代码,确保代码遵循良好的编程实践,如代码的封装、继承和多态。
- 优化类的设计,确保每个类都有单一职责,并且职责之间保持清晰的界限。
- 使用包和类层次结构来组织代码,保持清晰的命名规范,方便其他人理解。
(2)性能优化:
-
分析程序的性能瓶颈,并采取相应的优化措施。
-
对于频繁执行的计算,考虑使用更高效的算法或数据结构。
第八次题集
设计与分析:
这次迭代新加入了二极管类,但是类与类之间的基本关系没有变化,
基本类图如下:
本次添加的二极管类,如果正向接入则相当于闭合开关,反向接入则相当于开关打开,所以对于短路和断路这些情况的特殊判定也要增加,以下是部分代码:
class Diode extends Equipment implements Comparable<Diode> {private int pre;Diode(String name, int pre) {this.name = name;this.pre = pre;doidepre = pre;}@Overrideint getRatedcurrent() {return 8;}@Overridepublic void setVoltage(double c) {voltage = 0;}@Overridedouble getResistor() {return 0;}@Overridevoid display() {if (pre == 1) {System.out.print("@" + name + ":conduction" + " " + (int) contact1 + "-" + (int) contact2);} else {System.out.print("@" + name + ":cutoff" + " " + (int) contact1 + "-" + (int) contact2);}if (Ifexceed) {System.out.println(" exceeding current limit error");} else {System.out.println();}}@Overridepublic int compareTo(Diode o) {if (this.name.compareTo(o.getName()) < 0)return -1;elsereturn 1;}
}
其中变量pre就是前驱触脚,根据输入信息确定前驱触脚,然后在进行判断是否断开。
然后是电流的限制,就在电路设备类中都加入了一个方法getRatedcurrent(),用来获取额定电流,并通过方法Ifexceed分流,从而确定每一个电器是否超出限制。
以下是方法代码:
public void Ifexceed(double current) {for (int i = 0; i < list.size(); i++) {Equipment e = list.get(i);if (e instanceof Parallel) {e.Ifexceed(current);} else if (e instanceof Series) {e.Ifexceed(current);} else if (e instanceof Hswitch) {if (e.IfHswitchPath(this.name) && current > e.getRatedcurrent()) {e.Ifexceed = true;}} else {if (current > e.getRatedcurrent()) {e.Ifexceed = true;} elsee.Ifexceed = false;if(e instanceof Diode){if(current==0){e.Ifdiode=false;}else{e.Ifdiode=true;}}}}}
对每一条支路进行分流,确定它的电流,串联电路电流相等。
然后是管脚电压的计算,首先确定总路的电压,然后确定·总路中所有设备(当然也包括并联和串联等)的电压,
然后依次减去,可以得到每个用电器两端的电压,如果是并联或者串联,则继续调用相应方法。
主要判断短路和断路的情况,其中断路是还要考虑断开的设备的触脚电压可能是0,这需要额外判断。
同时注意这次题目将受控窗帘的默认情况改了,和上次不一样。
以下是计算的部分代码:
public void footvoltage(double v, double v1) {~~~double total = v;for (int i = 0; i < list.size(); i++) {Equipment e = list.get(i);if (e instanceof Governor || e instanceof ContinueGovernor)continue;else if (e instanceof Series) {e.footvoltage(total, total - e.getVoltage());total -= e.getVoltage();} else if (e instanceof Parallel) {e.footvoltage(total, total - e.getVoltage());total -= e.getVoltage();} else if (e instanceof Hswitch) {//有问题if (e.ifhswitch) {e.contact1 = total;if (e.IfHswitchPath2(this.name)) {e.contact2 = total - e.getVoltage();} else {e.contact3 = total - e.getVoltage();}total -= e.getVoltage();} else {if (e.IfHswitchPath2(this.name)) {e.contact2 = total;e.contact1 = total - e.getVoltage();} else {e.contact3 = total;e.contact1 = total - e.getVoltage();}total -= e.getVoltage();}} else {if (e.Ifrigth) {e.contact1 = total;e.contact2 = (total - e.getVoltage());total -= e.getVoltage();} else {e.contact2 = total;e.contact1 = (total - e.getVoltage());total -= e.getVoltage();}}}}
这只是正常的情况,断路和短路的代码过于繁琐,就不展示了。
最后还有一个短路检测,这个就很简单了,只有直接判断总路是不是短路,如果是直接输出就行,然后return。
if (mainPathway.Ifshort())//短路{System.out.println("short circuit error");return;}
踩坑心得:
这次题集难度很大,特殊情况也很多,所以真的踩了很多坑,以下是几个重点的坑:
(1) 首先是读题没有仔细看,想当然的以为窗帘这些受控电器没有变化和上次一样,结果它改了,默认情况改成了全开。
导致错了一个测试点,最后仔细看题终于发现了。
(2) 还有就是电路的电压触脚没有弄清楚,高中电路没有学好,如果并联的一条电路断路了,它的触脚电压可能为0,如果
他有多个断开的设备,则开头和结尾的断开设备中间的所有电器的触脚都是0。
例如输入:
#T1:[IN K1-1] [K1-2 OUT]
#T2:[IN K2-1] [K2-2 K3-1] [K3-2 B2-1] [B2-2 OUT]
#M1:[T1 T2]
#T3:[VCC M1-IN] [M1-OUT B1-1] [B1-2 GND]
#K1
end
错误输出:
@K1:closed 220-220 exceeding current limit error
@K2:turned on 220-0
@K3:turned on 0-220
@B1:200 220-0 exceeding current limit error
@B2:0 0-0
正确的输出:
@K1:closed 220-220 exceeding current limit error
@K2:turned on 220-0
@K3:turned on 0-220
@B1:200 220-0 exceeding current limit error
@B2:0 220-220
(3) 如果并联电路短路,则每条短路的电路均分电流,其他电路电流为0。
我下意识以为只会有一条短路电流,所有第一条短路会分全部电流,其他的则全部是0。
这就会导致电路设备是否超出电路限制做出影响。
例如输入:
#T1:[IN K1-1] [K1-2 OUT]
#T2:[IN K4-1] [K4-2 OUT]
#T4:[IN K3-1] [K3-2 OUT]
#M1:[T1 T2 T4]
#T3:[VCC K2-1] [K2-2 M1-IN] [M1-OUT B1-1] [B1-2 GND]
#K1
#K3
#K2
end
我的错误输出:
@K1:closed 220-220 exceeding current limit error
@K2:closed 220-220 exceeding current limit error
@K3:closed 220-220 exceeding current limit error
@K4:turned on 220-220
@B1:200 220-0 exceeding current limit error
正确输入为:
@K1:closed 220-220
@K2:closed 220-220 exceeding current limit error
@K3:closed 220-220
@K4:turned on 220-220
@B1:200 220-0 exceeding current limit error
改进建议:
(1)代码结构优化:
- 重构代码,确保代码遵循良好的编程实践,如代码的封装、继承和多态。
- 优化类的设计,确保每个类都有单一职责,并且职责之间保持清晰的界限。
- 使用包和类层次结构来组织代码,保持清晰的命名规范,方便其他人理解。
(2)性能优化:
-
分析程序的性能瓶颈,并采取相应的优化措施。
-
对于频繁执行的计算,考虑使用更高效的算法或数据结构。
-
在写代码时,加入多一些错误异常处理,这可以很好的帮助调试代码,发现错误。
总结
在本次家居强电电路模拟程序的迭代中,我主要关注了以下几个方面的改进:
- 电路复杂度的提升:我们引入了更复杂的电路结构,如多个串联的并联电路和包含串联电路的并联电路。这样的设计使得程序能够更真实地模拟现实生活中的电路布局。
- 新功能的加入:在第七次迭代中,我们增加了互斥开关和受控窗帘的功能。这些新功能的加入使得程序更加贴近实际应用,并为用户提供了更多的操作可能性。
- 代码结构的优化:在代码设计方面,我们采取了模块化设计、使用设计模式、文档和注释等措施,以提高代码的可读性和可维护性。
- 性能优化和错误处理:在第八次迭代中,我们优化了程序的性能,并引入了电流限制和短路检测等错误处理机制。这些改进使得程序更加健壮和可靠。
总的来说,这几次迭代确实很有锻炼效果,我能明显感觉到我的代码调试能力增强了,遇到错误会不断的测试,找到错误,然后修改。
我明白了持续学习的重要性。在未来项目开发过程中,我们可能遇到了许多新问题和挑战。为了找到解决方案,我不得不查阅相关资料,学习新的知识和技能。这种持续学习的过程让我不断进步,也让我意识到只有不断学习,才能适应不断变化的技术环境。
此外,我认识到编程不仅仅是一门技术,更是一种解决问题的能力。在项目开发过程中,我们需要面对各种各样的技术难题。通过不断尝试和思考,我们找到了解决问题的方法。这种解决问题的能力让我更加自信,也让我明白了编程的价值所在。
最后,我感激这几次PTA给我带来的成长和收获。在这个过程中,我提高了自己的编程技能,还收获了丰富的经验。这些经验和技能将对我未来的学习和职业发展产生深远的影响。