第一次OOP课程作业总结
一. 前言:
虽然学习JAVA仅有短短的三周,但收获的不仅有JAVA相关的知识还有解题后的成就感,趁着这次博客作业简单回顾一下这三周的心路历程吧,下面分别对三次作业做个简要分析。
(一) 第一次题目集:题目量虽然较多,有八道题,但其难度很低,都是很基础的题目,运用上学期学习的C语言知识再学习一些JAVA的基本语法,可以轻松解决这次题目集。
(二) 第二次题目集:题目量减少至五题,但难度有略微的提升。前两题难度较简单,7-3、7-4、7-5三道题环环相扣,难度依次增加,每一题都需要在上一题的基础上修改或是增加代码。我觉得还挺有趣的,很喜欢这类出题的方式。总体来说难度一般,考察的是逻辑思维能力。
(三) 第三次题目集:在这周,我已经开始学习运用类与对象编写程序。不得不说,在使用类与对象编写程序后,整个的代码的简洁程度有不小的增加,可读性大大提升,而且对于编写代码的我来说也更方便处理bug。题目量减少至三题,前两题难度一般,可最后一题难度暴增,整整花费我一周的时间才解决(心情复杂),不过也因这题,在和同学们的交流中我编写代码的能力获得了不少提升。
二. 设计与分析
(一) 第一次题目集
(1) 7-2 电话键盘字母数字转换
因为写第一次题目集时才初学JAVA,处理这道题时说实话还是挺头大的,没想到办法如何提取输入的字符串的第一个字母,后通过查阅相关资料,了解到一个s.charAt(i)语句,用该方法可以提取字符串s的第i个字符。随后几个简单的if else判断语句,这道题便就迎刃而解。
1 import java.util.Scanner; 2 3 public class Main { 4 5 public static void main(String[] args) { 6 // TODO Auto-generated method stub 7 Scanner in=new Scanner(System.in); 8 9 String s=in.nextLine(); 10 11 char zifu=s.charAt(0); 12 13 14 if((zifu >='a'&&zifu <= 'z')||(zifu >='A'&&zifu <= 'Z')) 15 { 16 if((zifu >='a'&&zifu <= 'c')||(zifu >='A'&&zifu <= 'C')) 17 System.out.print("2"); 18 else if((zifu >='d'&&zifu <= 'f')||(zifu >='D'&&zifu <= 'F')) 19 System.out.print("3"); 20 else if((zifu >='G'&&zifu <= 'I')||(zifu >='g'&&zifu <= 'i')) 21 System.out.print("4"); 22 else if((zifu >='j'&&zifu <= 'l')||(zifu >='J'&&zifu <= 'L')) 23 System.out.print("5"); 24 else if((zifu >='m'&&zifu <= 'o')||(zifu >='M'&&zifu <= 'O')) 25 System.out.print("6"); 26 else if((zifu >='p'&&zifu <= 's')||(zifu >='P'&&zifu <= 'S')) 27 System.out.print("7"); 28 else if((zifu >='t'&&zifu <= 'v')||(zifu >='T'&&zifu <= 'V')) 29 System.out.print("8"); 30 else if((zifu >='w'&&zifu <= 'z')||(zifu >='W'&&zifu <= 'Z')) 31 System.out.print("9"); 32 } 33 else 34 System.out.print(zifu+" is an invalid input"); 35 } 36 37 }
下图是SourceMonitor的生成报表,因为代码基本由多个if else语句组成,所以复杂度略高。

(2) 7-8 判断三角形类型
这题的难度主要体现在根据每类三角形的特点,例如一个直角三角形也可以是一个等角直角三角形,一个等腰三角形也可以是一个等腰直角三角形。当然,处理这道题并不困难,简单思考后便可以根据特点将三角形分类,只不过我的代码if else语句较多,可能不够简洁。
还有一个难点是在判断直角三角形时会存在一个精度损失的问题,这时直角边的平方之和不一定会等于斜边的平方,所以判断这种情况时需要些这两个平方相减小于一个极小的数值。
1 import java.util.Scanner; 2 3 public class Main { 4 5 public static void main(String[] args) { 6 // TODO Auto-generated method stub 7 Scanner in =new Scanner(System.in); 8 int i,j,min; 9 double temp; 10 double a[] = new double [3]; 11 for( i=0;i<3;i++) 12 { 13 a[i]=in.nextDouble(); 14 } 15 for(i=0;i<2;i++) 16 { 17 min=i; 18 for(j=i+1;j<3;j++) 19 { 20 if(a[j]<a[min]) 21 { 22 temp=a[j]; 23 a[j]=a[min]; 24 a[min]=temp; 25 } 26 } 27 } 28 if(a[0]<1||a[2]>200) 29 { 30 System.out.print("Wrong Format"); 31 } 32 else 33 { 34 if(a[0]+a[1]<=a[2]) 35 System.out.print("Not a triangle"); 36 else 37 { 38 if(a[0]==a[1]&&a[0]==a[2]&&a[1]==a[2]) 39 System.out.print("Equilateral triangle"); 40 else if(a[1]==a[2]) 41 System.out.print("Isosceles triangle"); 42 else if((a[0]*a[0]+a[1]*a[1])-a[2]*a[2]<0.000001) 43 { 44 if(a[0]==a[1]||a[1]==a[2]) 45 System.out.print("Isosceles right-angled triangle"); 46 else 47 System.out.print("Right-angled triangle"); 48 } 49 else if(a[0]==a[1]) 50 { 51 if((a[0]*a[0]+a[1]*a[1])==a[2]*a[2]) 52 System.out.print("Isosceles right-angled triangle"); 53 else 54 System.out.print("Isosceles triangle"); 55 } 56 else 57 System.out.print("General triangle"); 58 } 59 } 60 } 61 62 }

(二) 第二次题目集
(1)7-4 求下一天
这题难度主要考察逻辑思维能力,处理并判断好每一种情况,例如年底,月底,闰年二月月底等等一些情况。当全部情况都被列出后,题目也就被化繁为简,这在插入代码中的public static void nextDate(int year,int month,int day) 有体现。
其他的是一些较为基础的部分,判断输入是否合法,仅需一个简单的if(year >= 1820 && year <= 2020 && month >=1 && month <=12 && day <= dayOfMonth(year, month) && day >=1)语句;判断是否为闰年,也仅需一个简单的if(year % 4 == 0 && year % 100 != 0 || year % 400 == 0)语句。
1 import java.util.Scanner; 2 3 public class Main { 4 5 public static void main(String[] args) { 6 7 Scanner in = new Scanner(System.in); 8 9 int year = in.nextInt(); 10 int month = in.nextInt(); 11 int day = in.nextInt(); 12 13 if(checkInputValidity(year, month, day)) 14 nextDate(year, month, day); 15 else 16 System.out.println("Wrong Format"); 17 18 19 } 20 21 public static boolean isLeapYear(int year) { 22 boolean isLeap = false; 23 if(year % 4 == 0 && year % 100 != 0 || year % 400 == 0) 24 { 25 isLeap = true; 26 } 27 return isLeap; 28 } 29 30 31 32 public static boolean checkInputValidity(int year,int month,int day){ 33 boolean flag = false; 34 if(year >= 1820 && year <= 2020 && month >=1 && month <=12 && day <= dayOfMonth(year, month) && day >=1) 35 flag = true; 36 return flag; 37 } 38 39 40 public static int dayOfMonth(int year, int month) { 41 int Day = 0; 42 if(month == 1 || month == 3 || month == 5 || month == 7 || month == 8 || month == 10 || month == 12) 43 Day = 31; 44 else if(month == 4 || month == 6 || month == 9 || month == 11 ) 45 Day = 30; 46 else { 47 if(isLeapYear(year)) 48 Day = 29; 49 else 50 Day = 28; 51 } 52 return Day; 53 } 54 55 public static void nextDate(int year,int month,int day) { 56 57 if(month == 12) { 58 year +=1; 59 month = 1; 60 day = 1; 61 } 62 else if(day == dayOfMonth(year, month)){ 63 month +=1; 64 day =1; 65 } 66 else 67 day +=1; 68 System.out.println("Next date is:" + year + "-"+ month + "-" + day); 69 } 70 } 71
![]()
(2)7-5 求前N天
这题的难度相比上题又有小小提升,但大体思路相通,难度并不高。当N 为负数时,即为求下N天,仅需多做一个for循环;当N为正数时,需要添加一些额外情况的代码,例如,年初,闰年三月初,平年三月初等等。当然有了上一题的基础,最重要的是需要保证逻辑的清晰,想解决这道题也并不难。
1 import java.util.Scanner; 2 3 public class Main { 4 5 public static void main(String[] args) { 6 7 Scanner in = new Scanner(System.in); 8 9 int year = in.nextInt(); 10 int month = in.nextInt(); 11 int day = in.nextInt(); 12 int n =in.nextInt(); 13 14 if(checkInputValidity(year, month, day)) 15 nDate(year, month, day, n); 16 else 17 System.out.println("Wrong Format"); 18 19 20 } 21 22 public static boolean isLeapYear(int year) { 23 boolean isLeap = false; 24 if(year % 4 == 0 && year % 100 != 0 || year % 400 == 0) 25 { 26 isLeap = true; 27 } 28 return isLeap; 29 } 30 31 32 33 public static boolean checkInputValidity(int year,int month,int day){ 34 boolean flag = false; 35 if(year >= 1820 && year <= 2020 && month >=1 && month <=12 && day <= dayOfMonth(year, month) && day>=1 ) 36 flag = true; 37 return flag; 38 } 39 40 41 public static int dayOfMonth(int year, int month) { 42 int Day = 0; 43 if(month == 1 || month == 3 || month == 5 || month == 7 || month == 8 || month == 10 || month == 12) 44 Day = 31; 45 else if(month == 4 || month == 6 || month == 9 || month == 11 ) 46 Day = 30; 47 else { 48 if(isLeapYear(year)) 49 Day = 29; 50 else 51 Day = 28; 52 } 53 return Day; 54 } 55 56 public static void nDate(int year,int month,int day, int n) { 57 int N = 0; 58 if(n < 0){ 59 N = Math.abs(n); 60 61 while(N + day >=dayOfMonth(year, month)) { 62 if(month<12) { 63 N = day + N - dayOfMonth(year, month); 64 month += 1; 65 day = 0; 66 } 67 else if(month == 12) { 68 N = day + N - dayOfMonth(year, month); 69 year += 1; 70 month = 1; 71 day = 0; 72 } 73 74 } 75 } 76 else if(n > 0){ 77 N = n; 78 while(N >= dayOfMonth(year, month-1) + day) { 79 month -=1; 80 N -= dayOfMonth(year, month); 81 if(month == 1) { 82 year -=1; 83 month = 12; 84 N = dayOfMonth(year, month) + day - N; 85 } 86 87 } 88 if (N < day) { 89 N = N - day; 90 } 91 else { 92 if(month > 1) { 93 month -=1; 94 N = dayOfMonth(year, month) + day - N; 95 } 96 else if (month ==1) { 97 year -= 1; 98 month = 12; 99 N = dayOfMonth(year, month) + day - N; 100 } 101 102 103 } 104 } 105 else if (n == 0) { 106 System.out.println(n + " days ago is:" + year + "-"+ month + "-" + day); 107 System.exit(0); 108 } 109 System.out.println(n + " days ago is:" + year + "-"+ month + "-" + N); 110 } 111 } 112
![]()
(三) 第三次题目集
(1)7-2 定义日期类
本周作业开始采用类与对象编程,这题虽与上周的题目相同,但需要定义一个类Date,包含三个私有属性年(year)、月(month)、日(day)。此题难度极小,仅需做小小的修改。
1 import java.util.Scanner; 2 3 public class Main { 4 5 public static void main(String[] args) { 6 7 Scanner in = new Scanner(System.in); 8 int year = in.nextInt(); 9 int month = in.nextInt(); 10 int day = in.nextInt(); 11 Date date = new Date(year,month,day); 12 } 13 14 static class Date{ 15 private int year = 0; 16 private int month = 0; 17 private int day = 0; 18 int[] dayOfMonth = new int []{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; 19 20 public Date() { 21 22 } 23 24 public Date(int year, int month, int day) { 25 this.year = year; 26 this.month = month; 27 this.day = day; 28 29 if(checkInputValidity()) { 30 getNextDate(); 31 } 32 else { 33 System.out.print("Date Format is Wrong"); 34 } 35 } 36 37 boolean isLeapYear() { 38 boolean isLeap = false; 39 if(year % 4 == 0 && year % 100 != 0 || year % 400 == 0) 40 { 41 isLeap = true; 42 } 43 return isLeap; 44 } 45 46 boolean checkInputValidity(){ 47 boolean flag = false; 48 if(isLeapYear()) { 49 dayOfMonth[2] = 29; 50 } 51 if(year >= 1900 && year <= 2000 && month >=1 && month <=12 &&day <= dayOfMonth[month] && day >=1) { 52 flag = true; 53 } 54 return flag; 55 } 56 57 58 void getNextDate() { 59 60 if(month == 12 && day == dayOfMonth[month]) { 61 year +=1; 62 month = 1; 63 day = 1; 64 } 65 else if(day == dayOfMonth[month]){ 66 month +=1; 67 day =1; 68 } 69 else 70 day +=1; 71 System.out.println("Next day is:" + year + "-"+ month + "-" + day); 72 } 73 74 public int getYear() { 75 return year; 76 } 77 78 public void setYear(int year) { 79 this.year = year; 80 } 81 82 public int getMonth() { 83 return month; 84 } 85 86 public void setMonth(int month) { 87 this.month = month; 88 } 89 90 public int getDay() { 91 return day; 92 } 93 94 public void setDay(int day) { 95 this.day = day; 96 } 97 98 99 100 101 } 102 }
定义一个类后,代码的复杂度显著下降。
![]()

(2)7-3 一元多项式求导(类设计)
此题难度极大,花费了整整一周时间解决。
为方便理解,我将解释以注释的形式添加在代码中,下图展示的是该题的全部代码。
1 import java.math.BigInteger; 2 import java.util.Scanner; 3 import java.util.regex.Matcher; 4 import java.util.regex.Pattern; 5 6 7 public class QiuDao { 8 public static void main(String[] args){ 9 Scanner in = new Scanner(System.in); 10 String s = in.nextLine(); //存储输入的一元多项式 11 s = s.replaceAll(" ",""); //去除多项式中存在的空白 12 13 F test = new F (s); //定义一个新类型 14 15 } 16 17 18 static public class F{ 19 private String s = ""; 20 private BigInteger C =new BigInteger("1"); //方便进行大数处理的数字1 21 private int i = 0; 22 private int s1Length = 0; //存储与x有关的字符的字符串数组长度 23 private int s2Length = 0; //存储每一项的字符串数组长度 24 private int s3Length = 0; //系数与指数的长度 25 private String[] s1 = new String[100]; 26 private String[] s2 = new String[100]; 27 private String[] s3 = new String[100]; 28 29 public F() { 30 super(); 31 // TODO Auto-generated constructor stub 32 } 33 34 public F(String s) { 35 super(); 36 this.s = s; 37 checkTest(); 38 fallApart(); 39 qiuDao(); 40 changShu(); 41 outPut(); 42 } 43 44 //判断错误输入,检查多项式中有无系数或指数为0的情况出现 45 public void checkTest() { 46 if(s.indexOf("+0*")!=-1||s.indexOf("^0")!=-1||s.indexOf("-0*")!=-1){ 47 System.out.print("Wrong Format"); 48 System.exit(0); //输入错误则直接结束程序 49 } 50 } 51 52 //分离系数、指数、字符 53 public void fallApart() { 54 //字符部分,取出多项式中与x相关的字符 55 i = 0; 56 Pattern p1 = Pattern.compile("([+-]?x\\^)|(\\*x\\^)|(\\*x)|[+-]{1}x|^x[+-]{1}"); 57 Matcher m1 = p1.matcher(s); 58 while(m1.find()){ 59 s1[i] = m1.group(); 60 i++; 61 } 62 s1Length = i; 63 64 65 //取出多项式中的每一项 66 i = 0 ; 67 Pattern p2 = Pattern.compile("((([+-]?[1-9]+[0-9]*))?|[-]?)\\*[x](\\^([+-]?[1-9]+[0-9]*))?+|(x\\^[+-]?[0-9]+)|[+-]?x\\^[+-]?d+"); 68 Matcher m2 = p2.matcher(s); 69 while(m2.find()){ 70 s2[i] = m2.group(); 71 i++; 72 } 73 s2Length = i; 74 75 //取出每一项中的系数与指数 76 i = 0; 77 Pattern p3 = Pattern.compile("[+-]?\\d+"); 78 for(int k = 0; k < s2Length; k++) { 79 Matcher m3 = p3.matcher(s2[k]); 80 while(m3.find()){ 81 s3[i] = m3.group(); 82 i++; 83 } 84 } 85 s3Length = i; 86 87 88 // 曾被用于遍历上面的三个字符串数组,以确保数据存储正确 89 // for(i = 0; i<s1Length; i++) { 90 // System.out.println(s1[i] + " " + i); 91 // } 92 // for(i = 0; i<s2Length; i++) { 93 // System.out.println(s2[i] + " " + i); 94 // } 95 // for(i = 0; i<s3Length; i++) { 96 // System.out.println(s3[i] + " " + i); 97 // } 98 } 99 100 //求导 101 public void qiuDao() { 102 i=0; 103 for(int j = 0; j<s1Length; j++,i++ ) { 104 if(s1[j].equals("*x^")) { 105 //处理大数的问题,求导后系数乘指数,指数减一 106 BigInteger A = new BigInteger(s3[i]); 107 BigInteger B = new BigInteger(s3[i+1]); 108 s3[i] = A.multiply(B).toString(); 109 s3[i+1] =B.subtract(C).toString(); 110 i=i+1; //这种类型带有系数和指数两个数字,需要存数字的字符串数组额外加一 111 } 112 else if(s1[j].equals("-x")) { 113 i--; //这种类型不带指数和系数,所以 i-1,下面三个同理 114 } 115 else if(s1[j].equals("+x")) { 116 i--; 117 } 118 else if(s1[j].equals("x-")||s1[j].equals("x+")||s1[j].equals("x")) { 119 i--; 120 } 121 } 122 } 123 124 //仅有常数,根据存储数据的两个字符串数组的长度来判断 125 public void changShu() { 126 if(s3Length == 0 && s1Length == 0 ) { 127 System.out.print(0); //输出0,常数求导为0 128 } 129 } 130 131 132 //输出,根据每种类型的求导后的结果输出相应的相应的式子 133 public void outPut() { 134 i = 0; 135 for(int j = 0; j<s1Length;j++,i++) { 136 if(s1[j].equals("*x^")) { 137 if(s3[i].indexOf("-") == -1&& j != 0&&!s3[i+1].equals("0")) { 138 System.out.print("+"); //不是首项且系数不为负数的情况,需要添加加号来连接两个项 139 } 140 if(s3[i+1].equals("1")) { 141 System.out.print(s3[i] + "*x"); //指数为1 142 } 143 else if(s3[i+1].equals("0")) { 144 System.out.print(Integer.parseInt(s3[i])); //指数为0 145 } 146 else 147 System.out.print(s3[i] + "*x^" + s3[i+1]); //非特殊情况 148 i++; 149 } 150 else if(s1[j].equals("*x")){ 151 152 System.out.print(Integer.parseInt(s3[i])); 153 154 } 155 else if(s1[j].equals("+x^")||s1[j].equals("x^")) { 156 if(Integer.parseInt(s3[i]) > 0 && j != 0 && Integer.parseInt(s3[i]) != 1) { 157 System.out.print("+"); 158 } 159 if((Integer.parseInt(s3[i]) == -1)) 160 System.out.print("-x^" + (Integer.parseInt(s3[i])-1)); 161 else if((Integer.parseInt(s3[i]) == 2)) { 162 System.out.print(s3[i] + "*x"); 163 } 164 else if(Integer.parseInt(s3[i]) == 1){ 165 System.out.print(Integer.parseInt(s3[i])); 166 } 167 else 168 System.out.print(Integer.parseInt(s3[i]) + "*x^" + (Integer.parseInt(s3[i])-1)); 169 } 170 else if(s1[j].equals("-x^")) { 171 if((Integer.parseInt(s3[i]) > 2)) 172 System.out.print("-" + s3[i] + "*x^" + (Integer.parseInt(s3[i])-1)); 173 else if((Integer.parseInt(s3[i]) == 2)) 174 System.out.print("-" + s3[i] + "*x"); 175 else if((Integer.parseInt(s3[i]) == 1)) 176 System.out.print("-" + s3[i]); 177 else if((Integer.parseInt(s3[i]) <= -1)) 178 System.out.print("+" + Integer.parseInt(s3[i])*-1 + "*x^" + (Integer.parseInt(s3[i])-1)); 179 } 180 else if(s1[j].equals("-x")) { 181 System.out.print("-1"); 182 i--; 183 } 184 else if(s1[j].equals("+x")) { 185 System.out.print("1"); 186 i--; 187 } 188 else if(s1[j].equals("x-")||s1[j].equals("x+")||s1[j].equals("x")) { 189 System.out.print("1"); 190 i--; 191 } 192 } 193 194 } 195 } 196 197 198 199 }
代码较为复杂且不够简洁
![]()

三. 踩坑心得
(一)求前N天
起初没用仔细审题,忽略了N为负数或0的情况,补充该情况的代码后程序正常运行。

(二)一元多项式求导(类设计)
此题难度极大,整整花费了一周多的时间解决。其难度主要体现在如何取出多项式的每一项,如何取出系数和指数以及其符号,如何对取出的数字进行处理,以及如何符合题意输出求导后的式子。
首先我想到的是用split语句将输入的字符串分割成两个字符数组,一个用于存储数字,一个用于存储与x相关的字符,再根据特殊的字符组合如 “*x^”、"*x"、"x"对其系数指数进行求导处理,但随后发现这个思路存在很多问题。字符数组仅能存一位数,二位数就无法处理了,而且不方便判断数字的正负。
后决定采用正则表达式按需要取出数字(包括其正负号)和与x有关的字符存于两个字符串数组,所以引入两个类java.util.regex.Matcher和java.util.regex.Pattern,再按求导方式对数字进行处理,但无法通过多项式中间有常数的情况和大数情况。原因是Pattern p3 = Pattern.compile("[+-]?\\d+")会取出所有的数字,包括中间的常数,所以我又添加了一个规则Pattern p2 = Pattern.compile("((([+-]?[1-9]+[0-9]*))?|[-]?)\\*[x](\\^([+-]?[1-9]+[0-9]*))?+|(x\\^[+-]?[0-9]+)|[+-]?x\\^[+-]?d+"),这个规则会将多项式分成一个个的子项,我再对子项做取数字的操作,这样就可以避免取到常数项,而且还简化了代码,删去了判断首项是否为常数的代码。大数情况,引入java.math.BigInteger后,大数测试点也可以正常通过。


四. 改进建议
关于这个问题我有思考很久,思来想去发现我的代码存在着很多普遍性问题,是每一题可能都会犯的。下面列出部分以强化记忆。
(一)缺少缺少分号右括号等符号,导致程序报错。这个问题是常常会犯的,不过好在处理起来并不困难,但还是需要注意然后避免这个小问题。
(二)不能仔细审视题目,会忽略边界值,导致代码不能通过PTA测试点,尤其是求天数的那一类题目中。不过在第三周时这类情况有减少很多,做一元多项式求导时也会首先考虑到错误输入的一些情况。
(三)代码复杂度高,不够简洁。这个问题一直存在,但很难避免,想解决这个问题需要不断的学习不断的练习,我会在接下来的学习道路上继续努力的。
(四) 自觉完成题目的时间较长,对JAVA理论的实际应用能力还不足,需要查资料来编写代码。其实这倒不是什么坏事,现在所学的知识并不多,查资料也无可厚非,只是要查完资料后将其记于脑中!!
五. 总结
(一) 循环结构、控制结构、构造方法、方法的调用、参数传递以及对象的构造与使用,都已基本理解如何使用,可以自己现在可以独立编写出结构清晰且符合题意的代码。
(二) 学会了编写结构清晰的代码和填写适当注释以确保代码的可读性,会使用debug功能和自己输入数据测试来检测代码的功能是否完善。
(三) 杂谈:JAVA是一种面向对象的操作语言,一定一定要懂得其特性,不能完全照搬上学期学习C语言的学习方式。学习JAVA,首先要多看代码,多多分析别人的代码,理解他们的思路,然后自己动手编写代码,将所学的知识应用于编程中。遇到问题可以上网查找相关的知识点或是和同学交流,这些都可以帮助我在学习JAVA的道路上快速前行。现在的我仅仅学习Java语言的一些皮毛,想真正掌握Java技术,需要在平时的学习中坚持并下苦功夫。毕竟,想要掌握知识,少不了长期的积累和实践!
浙公网安备 33010602011771号