Blog1_单部电梯调度

前言
这三次 PTA 电梯调度的作业就像闯关一样,后两次都是在前一次的基础上升级难度。第一次最关键,光是搞懂电梯的运行逻辑就花了不少时间,因为它和平时坐的电梯不太一样。写代码的时候更是状况百出,比如怎么把输入的字符串里的数字、字母和符号分开提取出来,为此现学了正则表达式和列表的用法,中间还经常发现逻辑错误或者漏掉某些情况。到了第二、三次作业,主要是给第一次的代码 “打补丁”,比如按要求设计不同的类,处理更多特殊情况,三次作业一步一步下来,边写边学了很多新东西。
一、各次作业情况

  1. 第一次作业
    学的东西:
    设计了一个电梯类,里面记录电梯的当前楼层、运行方向、状态,还有里面和外面的请求列表。
    电梯状态分上行、下行、停止、开门、关门这些,请求列表用队列存起来,外面的请求还要分上楼和下楼的。
    用了 LOOK 算法,简单说就是电梯会先把同方向的请求处理完,才会转向。
    题量:就一道题,但要实现的功能挺多,逻辑有点绕。
    难度:中等,难在理清电梯怎么跑,还有处理输入的字符串。
  2. 第二次作业
    学的新东西:
    要把不同的功能分到不同的类里,比如电梯类、请求类、队列类、控制类,每个类只做一件事(单一职责原则)。 还要处理异常情况,比如有人按了不存在的楼层,或者连续按同一个楼层,得报错提示。 用链表来存请求列表,方便添加和删除。 题量:还是一道题,但除了功能还要注意类的设计。
    难度:比较难,要想怎么把功能分到不同的类里,还要处理各种奇怪的请求。
  3. 第三次作业
    学的新东西: 把请求类换成了乘客类,记录乘客的起点和终点。 输入格式变了,外面的请求写成 “<起点,终点>”,要把这两个楼层分开解析,而且电梯到了起点后,还要把终点加到里面的请求列表里。
    题量:一道题,但要调整之前的类和请求处理逻辑。
    难度:比较难,主要是改类和请求的处理流程,得保证逻辑连贯。
    二、整体感受
  4. 学到的知识点 最大的感受是 “一个类只干一件事”,这样代码更清楚,比如电梯类只管电梯怎么跑,请求类只管记录请求。 用了先进先出的队列和链表来存请求,方便按顺序处理。 还学会了用 ArrayList 和正则表达式处理输入的字符串,比如把 “<1,UP><2,DOWN>” 拆成楼层和方向。
  5. 题量和心态 一开始觉得题量很大,特别是第一次,看着复杂的要求有点懵。但后来发现,第二次、第三次其实是在第一次的基础上改,比如加个类、调个逻辑,代码改动没想象中那么多。心态很重要,越熟悉逻辑,越觉得题量其实能接受,甚至后面改起来还挺顺手。
  6. 遇到的难点 最难的是电梯什么时候转向,比如往上走的时候,得先看完上面有没有要上或下的人,都处理完了才能往下走,得仔细判断各种情况。 多个类之间怎么配合也有点难,比如乘客类的请求怎么传给电梯类,队列类怎么通知电梯处理请求,得慢慢理清它们之间的关系。 不过一旦把第一次的逻辑搞懂了,后面两次虽然难,但跟着要求一步步改,也能完成,每次改完代码运行成功都很有成就感。
    二、设计与分析
    第一次电梯题目的设计与分析
    题目要求:
    设计一个电梯类,具体包含电梯的最大楼层数、最小楼层数(默认为1层)当前楼层、运行方向、运行状态,以及电梯内部乘客的请求队列和电梯外部楼层乘客的请求队列,其中,电梯外部请求队列需要区分上行和下行。
    电梯运行规则如下:电梯默认停留在1层,状态为静止,当有乘客对电梯发起请求时(各楼层电梯外部乘客按下上行或者下行按钮或者电梯内部乘客按下想要到达的楼层数字按钮),电梯开始移动,当电梯向某个方向移动时,优先处理同方向的请求,当同方向的请求均被处理完毕然后再处理相反方向的请求。电梯运行过程中的状态包括停止、移动中、开门、关门等状态。当电梯停止时,如果有新的请求,就根据请求的方向或位置决定移动方向。电梯在运行到某一楼层时,检查当前是否有请求(访问电梯内请求队列和电梯外请求队列),然后据此决定移动方向。每次移动一个楼层,检查是否有需要停靠的请求,如果有,则开门,处理该楼层的请求,然后关门继续移动。
    使用键盘模拟输入乘客的请求,此时要注意处理无效请求情况,例如无效楼层请求,比如超过大楼的最高或最低楼层。还需要考虑电梯的空闲状态,当没有请求时,电梯停留在当前楼层。
    请编写一个Java程序,设计一个电梯类,包含状态管理、请求队列管理以及调度算法,并使用一些测试用例,模拟不同的请求顺序,观察电梯的行为是否符合预期,比如是否优先处理同方向的请求,是否在移动过程中处理顺路的请求等。为了降低编程难度,不考虑同时有多个乘客请求同时发生的情况,即采用串行处理乘客的请求方式(电梯只按照规则响应请求队列中当前的乘客请求,响应结束后再响应下一个请求)
    输入格式:
    第一行输入最小电梯楼层数。
    第二行输入最大电梯楼层数。
    从第三行开始每行输入代表一个乘客请求。
    • 电梯内乘客请求格式:<楼层数>
    • 电梯外乘客请求格式:<乘客所在楼层数,乘梯方向>,其中,乘梯方向用UP代表上行,用DOWN代表下行(UP、DOWN必须大写)。
    • 当输入“end”时代表输入结束(end不区分大小写)。
    输出格式:
    模拟电梯的运行过程,输出方式如下:
    • 运行到某一楼层(不需要停留开门),输出一行文本:
    Current Floor: 楼层数 Direction: 方向
    • 运行到某一楼层(需要停留开门)输出两行文本:
    Open Door # Floor 楼层数
    Close Door
    类的设计思路:
    1.枚举类定义方向(UP/DOWN/NONE)和状态(STOPPED/MOVING等),增强代码可读性。
  7. Request类封装请求楼层与方向,区分内部(轿厢按钮)和外部(楼层按钮)请求。
  8. Elevator类维护电梯状态(当前楼层、运行方向等)和请求队列(LinkedList实现),通过determineDirection计算运行方向,按规则(同向优先、最高层优先)处理请求,移动时输出楼层变化,到达时开关门。
  9. Main类读取输入,解析请求格式(内部[楼层]或外部<楼层,方向>),调用电梯处理逻辑。
    整体结构清晰,通过队列管理请求,按简单调度策略实现电梯运行模拟。

    SourceMonitor分析:
    复杂度分析
  10. Elevator.determineDirection方法
    从给出的度量指标图可知,Elevator.determineDirection方法的复杂度数值高达34 。在代码中,这个方法承担着确定电梯运行方向的关键任务。由于电梯运行方向需综合考量内部请求与外部请求的多种组合情形,导致逻辑分支极为繁杂。
    具体来说,既要判别内部请求楼层与当前楼层的高低关系,又要顾及外部请求楼层的相应情况,以及内外部请求各自的方向等要素。这使方法内部充斥着大量的if - else条件判断语句,层层嵌套损害了代码的可读性。一旦需求发生变动,对该方法进行修改极易引发逻辑错误。
  11. 其他方法
    Elevator.processRequests方法复杂度为22 ,Main.main方法复杂度为9 。复杂度数值直观地反映了方法内部逻辑的复杂程度。以Elevator.processRequests方法为例,其在处理电梯请求的过程中,需依据电梯的运行方向、请求队列等诸多因素进行逻辑判断与操作,这必然导致其中存在大量的条件判断语句与循环语句,进而促使复杂度上升。而Main.main方法作为程序的入口,虽复杂度相对较低,但也需承担处理用户输入、初始化电梯对象等一系列任务,其复杂度同样在一定程度上体现了这些操作逻辑的复杂性。

语句数量分析

  1. Elevator.determineDirection方法
    Elevator.determineDirection方法的语句数多达44 。这表明该方法内部代码行数众多,逻辑冗长繁琐。。从代码模块化的视角来看,大量语句集中于一个方法内,不利于代码的拆分与复用,可以将其中功能相对独立的代码片段抽取出来,封装成更小的方法,能够显著提升代码的可读性,还能增强代码的可维护性。
  2. Elevator.processRequests方法
    Elevator.processRequests方法的语句数为40 ,同样存在语句数量偏多的问题。该方法在实现电梯请求处理的过程中,涵盖了电梯运行方向的确定、楼层的移动、停靠判断等多个环节,每个环节都需一定数量的语句予以实现。众多语句相互交织,致使代码逻辑不够清晰明了。
    最大深度分析
  3. Elevator.determineDirection方法
    Elevator.determineDirection方法的最大深度为5 。这意味着在该方法内部存在较多的嵌套结构,诸如if语句的多层嵌套,或者循环语句内部嵌套if语句等情况。这种多层嵌套的结构使得程序执行流程错综复杂,犹如迷宫一般。在理解代码逻辑时,难以清晰梳理出从起始到结束的完整路径。当代码出现问题需要调试时,由于嵌套层次较多,难以精准判定是哪一层嵌套中的代码出现错误,极大地增加了调试的难度与时间成本。
  4. Elevator.processRequests方法
    Elevator.processRequests方法的最大深度达到7 ,嵌套结构更为复杂。在该方法中,既要依据电梯运行方向执行不同操作,又要在操作过程中不断判断是否满足停靠条件等,这些逻辑的实现高度依赖大量的嵌套结构。过多的嵌套不仅使代码结构混乱不堪。当需要在该方法中增添新的功能或逻辑时,鉴于现有的嵌套结构已然十分复杂,新代码的融入可能会使整个方法变得更加晦涩难懂、难以维护。
    第二次电梯题目的设计与分析
    题目要求:
    对之前电梯调度程序进行迭代性设计,目的为解决电梯类职责过多的问题,类设计要求遵循单一职责原则(SRP),要求必须包含但不限于设计电梯类、乘客请求类、队列类以及控制类,另外,PTA得分代码界定为第一次提交的最高分代码(因此千万不要把第一次电梯程序提交到本次题目中测试)。
    输入格式:
    第一行输入最小电梯楼层数。
    第二行输入最大电梯楼层数。
    从第三行开始每行输入代表一个乘客请求。
    • 电梯内乘客请求格式:<楼层数>
    • 电梯外乘客请求格式:<乘客所在楼层数,乘梯方向>,其中,乘梯方向用UP代表上行,用DOWN代表下行(UP、DOWN必须大写)。
    • 当输入“end”时代表输入结束(end不区分大小写)。
    输出格式:
    模拟电梯的运行过程,输出方式如下:
    • 运行到某一楼层(不需要停留开门),输出一行文本:
    Current Floor: 楼层数 Direction: 方向
    • 运行到某一楼层(需要停留开门)输出两行文本:
    Open Door # Floor 楼层数
    Close Door
    类图:

    类的设计思路:
    枚举类 Direction 和 State
    Direction:定义了电梯的运行方向,包含 UP(向上)、DOWN(向下)和 IDLE(静止)三种状态。使用枚举类型可以使代码更具可读性和可维护性,避免使用硬编码的字符串或整数。
    State:定义了电梯的运行状态,包含 STOPPED(停止)和 MOVING(运行)两种状态。同样,枚举类型有助于清晰地表示不同状态。

类 Elevator
功能:该类代表电梯,负责管理电梯的当前楼层、运行方向、运行状态以及楼层范围。
属性:
currentFloor:记录电梯当前所在的楼层,初始值为 1。
direction:表示电梯的运行方向,类型为 Direction 枚举。
state:表示电梯的运行状态,类型为 State 枚举。
minFloor 和 maxFloor:分别表示电梯可到达的最低楼层和最高楼层。
方法:
提供了获取和设置各个属性的方法,如 getCurrentFloor()、setCurrentFloor(int currentFloor) 等。
isValidFloor(int floor):用于检查输入的楼层是否在电梯可到达的范围内。

类 ExternalRequests
功能:该类代表外部请求,即乘客在电梯外按下按钮发出的请求。
属性:
floor:表示请求所在的楼层。
direction:表示请求的方向,类型为 Direction 枚举。
方法:提供了获取 floor 和 direction 的方法。

类 RequestQueue
功能:该类负责管理电梯的请求队列,包括内部请求(乘客在电梯内按下的楼层按钮)和外部请求。
属性:
internalRequests:使用 LinkedList 存储内部请求的楼层。
externalRequests:使用 LinkedList 存储外部请求。
方法:
提供了获取和设置请求队列的方法,如 getInternalRequests()、setInternalRequest(LinkedList intnalRequests) 等。
addInternalRequest(int floor):向内部请求队列中添加一个请求。
addExternalRequest(int floor, Direction direction):向外部请求队列中添加一个请求。
hasRequests():检查队列中是否还有未处理的请求。

类 Controller
功能:该类是电梯系统的核心控制器,负责处理请求、确定电梯的运行方向、移动电梯以及处理开门和关门等操作。
属性:
elevator:表示要控制的电梯对象。
queue:表示请求队列对象。
方法:
processRequests():处理队列中的所有请求,直到队列为空。在处理过程中,会调用 determineDirection() 确定电梯的运行方向,调用 move() 移动电梯,根据 shouldStop(int floor) 判断是否需要停止并开门,最后调用 removeRequests(int currentFloor) 移除已处理的请求。
getClosest(Integer a, Integer b, int currentFloor):用于计算两个楼层中哪个离当前楼层更近。
getNextFloor():根据当前电梯的位置和运行方向,从请求队列中选择下一个要到达的楼层。优先考虑同方向的请求,如果同方向没有请求,则考虑反方向或当前楼层的请求。
determineDirection():根据下一个要到达的楼层,确定电梯的运行方向。
openDoors():模拟电梯开门操作,输出开门信息。
move():根据电梯的运行方向,将电梯移动到下一个要到达的楼层,并输出每一层的信息。
shouldStop(int floor):判断电梯是否需要在当前楼层停止。如果内部请求队列中包含当前楼层,或者外部请求队列中当前楼层的请求方向与电梯运行方向一致,则需要停止。
removeRequests(int currentFloor):从请求队列中移除已处理的请求。

类 Main
功能:该类是程序的入口点,负责读取用户输入的最低楼层、最高楼层和请求信息,并将请求添加到请求队列中。最后调用 Controller 的 processRequests() 方法处理所有请求。
流程:

  1. 使用 Scanner 读取用户输入的最低楼层和最高楼层。

  2. 创建 Elevator、RequestQueue 和 Controller 对象。

  3. 循环读取用户输入,直到输入 end 为止。

  4. 根据输入的格式判断是内部请求还是外部请求,并将其添加到请求队列中。

  5. 调用 controller.processRequests() 处理所有请求。
    SourceMonitor分析:
    第三次电梯题目的设计与分析
    题目要求:
    对之前电梯调度程序再次进行迭代性设计,加入乘客类(Passenger),取消乘客请求类,类设计要求遵循单一职责原则(SRP),要求必须包含但不限于设计电梯类、乘客类、队列类以及控制类,
    电梯运行规则与前阶段相同,但有如下变动情况:
    • 乘客请求输入变动情况:外部请求由之前的<请求楼层数,请求方向>修改为<请求源楼层,请求目的楼层>
    • 对于外部请求,当电梯处理该请求之后(该请求出队),要将<请求源楼层,请求目的楼层>中的请求目的楼层加入到请求内部队列(加到队尾)
    注意:本次作业类设计必须符合如上要求(包含但不限于设计电梯类、乘客类、队列类以及控制类),凡是不符合类设计要求此题不得分,另外,PTA得分代码界定为第一次提交的最高分代码(因此千万不要把第一次及第二次电梯程序提交到本次题目中测试)。
    输入格式:
    第一行输入最小电梯楼层数。
    第二行输入最大电梯楼层数。
    从第三行开始每行输入代表一个乘客请求。
    • 电梯内乘客请求格式:<楼层数>
    • 电梯外乘客请求格式:<请求源楼层,请求目的楼层>,其中,请求源楼层表示乘客发起请求所在的楼层,请求目的楼层表示乘客想要到达的楼层。
    • 当输入“end”时代表输入结束(end不区分大小写)。
    输出格式:
    模拟电梯的运行过程,输出方式如下:
    • 运行到某一楼层(不需要停留开门),输出一行文本:
    Current Floor: 楼层数 Direction: 方向
    • 运行到某一楼层(需要停留开门)输出两行文本:
    Open Door # Floor 楼层数
    Close Door
    类图:

    类的设计思路

  6. Elevator 类
    功能定位:该类代表电梯实体,负责管理电梯的当前楼层、运行方向、运行状态以及楼层范围。
    成员变量:
    currentFloor:记录电梯当前所在楼层,初始值为 1。
    direction:表示电梯的运行方向,借助 Direction 枚举类型定义,有 UP、DOWN、IDLE 三种状态。
    state:代表电梯的运行状态,使用 State 枚举类型定义,有 STOPPED、MOVING 两种状态。
    minFloor 和 maxFloor:界定电梯可到达的最小和最大楼层。
    方法:
    构造方法:接收 minFloor 和 maxFloor 作为参数,对电梯的楼层范围进行初始化。
    getElevatorInstance:此方法可创建并返回一个新的 Elevator 实例。
    一系列的 get 和 set 方法:用于获取和设置电梯的属性。
    isValidFloor:检查给定楼层是否在电梯可到达的楼层范围内。

  7. Passenger 类
    功能定位:该类代表乘客,负责管理乘客的起始楼层和目标楼层。
    成员变量:
    sourceFloor:记录乘客所在的起始楼层。
    destinationFloor:记录乘客要前往的目标楼层。
    方法:
    构造方法:接收 sourceFloor 和 destinationFloor 作为参数,对乘客的起始楼层和目标楼层进行初始化。
    一系列的 get 和 set 方法:用于获取和设置乘客的属性。

  8. RequestQueue 类
    功能定位:该类用于管理电梯的内外请求队列。
    成员变量:
    internalRequests:存储电梯内部乘客按下的目标楼层请求,采用 LinkedList 存储。
    externalRequests:存储电梯外部乘客的请求,每个请求是一个 Passenger 对象,同样采用 LinkedList 存储。
    方法:
    getQueueInstance:返回当前的 RequestQueue 实例。
    一系列的 get 和 set 方法:用于获取和设置请求队列。
    addInternalRequest:向内部请求队列添加一个目标楼层请求。
    addExternalRequest:向外部请求队列添加一个乘客请求。
    hasRequests:检查请求队列中是否存在未处理的请求。

  9. Controller 类
    功能定位:该类是电梯系统的核心控制类,负责处理请求、确定电梯运行方向、移动电梯以及处理开门关门等操作。
    成员变量:
    elevator:指向要控制的 Elevator 实例。
    queue:指向存储请求的 RequestQueue 实例。
    方法:
    构造方法:接收 elevator 和 queue 作为参数,对控制器进行初始化。
    一系列的 get 和 set 方法:用于获取和设置电梯和请求队列。
    processRequests:处理请求队列中的所有请求,包含确定电梯运行方向、移动电梯、判断是否停止、开门关门以及移除已处理的请求等操作。
    getClosest:在两个楼层中找出距离当前楼层最近的楼层。
    getNextFloor:依据当前电梯的运行方向和请求队列,确定下一个要到达的楼层。
    determineDirection:根据下一个要到达的楼层,确定电梯的运行方向。
    openDoors:模拟电梯开门操作并输出信息。
    move:根据电梯的运行方向,将电梯移动到下一个要到达的楼层。
    shouldStop:判断电梯是否应该在当前楼层停止。
    removeRequests:移除当前楼层的已处理请求,并将外部请求中的乘客目标楼层添加到内部请求队列。

  10. Main 类
    功能定位:该类是程序的入口点,负责初始化电梯系统、读取用户输入的请求并启动请求处理流程。
    方法:
    main 方法:
    读取用户输入的最小楼层和最大楼层,创建 Elevator 实例。
    创建 RequestQueue 和 Controller 实例。
    持续读取用户输入的请求,直到用户输入 end 为止。
    处理用户输入的请求,将内部请求和外部请求分别添加到相应的请求队列中。
    调用 controller.processRequests() 处理请求队列中的所有请求计思路:

一、踩坑心得

  1. 算法设计逻辑偏差
    • 问题描述
    首次设计电梯调度算法时,错误沿用历遍队列所有元素的逻辑,未聚焦 “仅比较头指针” 的核心规则。导致算法复杂度增加,每日推翻方案重写,同时未与同学交流,自己埋头苦干,浪费大量时间。
    • 解决过程
    通过阅读题目示例及调试简单用例(如单一方向连续请求)与同学一起讨论,发现电梯只需根据当前运行方向优先处理对应方向的队列头请求,逐步剥离冗余逻辑,聚焦 “方向 + 头指针” 的核心判断。
  2. 运行超时问题
    • 第一次作业:死循环导致超时
    做第一次作业时未考虑太多,忽略了边界和特殊情况,循环逻辑有问题,陷入死循环,导致运行超时,改完一个超时还有下一个,心累。

• 解决过程
不断测试其他用例,输出可能出现错误的地方,进行单步调试。

3.请求队列去重逻辑错误
• 问题描述:题目要求 “过滤连续相同请求”,但误判为 “删除队列中所有重复请求”。
• 解决过程
修改代码,仅跳过连续重复。

  1. 外部请求与内部请求关联缺失
    问题描述在处理题目集 07 时,两个关键测试用例出现异常:
    • 测试用例 1:电梯执行外部请求 “+4UP” 时,提前在 4 楼停靠,未继续处理后续内部请求(如目的地 5 楼)。
    • 测试用例 2:处理外部请求 “+9DOWN” 时,电梯到达 9 楼后停止,未响应后续 8 楼的向下请求。
    通过调试发现,外部请求出队时未将乘客目的地正确加入内部请求队尾,导致电梯完成乘梯请求后无后续目标,提前结束当前方向运行。
    • 解决过程
    1.定位问题:通过打印队列状态,发现外部请求处理后内部队列为空,电梯因无目的地请求而停止。
  2. 逻辑修正:明确外部请求仅表示 “乘梯请求”,乘客进入电梯后需生成对应的 “目的地请求”(内部队列)。
  3. 代码改进:在外部请求处理时,将登梯楼层或解析到的目的地加入内部队列

    四、改进建议

在代码优化方面,需简化算法逻辑,避免过多分支语句导致的可读性下降,可通过梳理核心流程、提炼状态规则让逻辑更清晰。编写代码时应遵循单一职责原则,将功能模块化,使每个模块专注于一项任务,以此提升代码的可读性与可维护性,为后续迭代奠定基础。同时,要注重提升算法思维能力,深入理解需求并冷静分析问题,避免因逻辑复杂而陷入困境。

需求分析是程序设计的基石,需投入足够时间理清问题边界与功能点,确保对要解决的问题和实现的功能有完整认知,避免因需求模糊导致代码设计偏离方向。在代码规范上,应增加必要注释,清晰标注关键逻辑与功能意图,防止后期因代码理解困难影响维护效率。处理输入时可采用更高效的方式,如借助正则表达式提升文本处理的准确性和简洁性,减少因输入解析复杂带来的代码冗余。

对于状态管理,使用枚举类型替代字符串硬编码,能增强代码的安全性与可靠性,降低因状态值错误引发的问题风险。在开发流程中,可采用“需求分析—流程图—伪代码—代码”的步骤,先通过可视化工具梳理逻辑框架,再逐步实现,避免直接编码导致的逻辑混乱。调试能力的提升也至关重要,利用开发工具的断点调试功能跟踪变量状态,结合测试用例覆盖多类场景,可有效定位并解决逻辑错误。

团队协作方面,应主动加强交流,通过分享问题与借鉴经验拓宽思维方式,避免单打独斗带来的局限性,同时从他人解决方案中汲取灵感,优化自身代码设计。在能力提升上,针对薄弱环节制定学习计划,如补足编程语言基础、理解设计模式思想,通过系统性学习逐步提升编程素养,为复杂问题的解决积累能力。总之,需从逻辑优化、结构规范、流程管理、团队协作等多维度入手,持续改进代码质量与开发效率。
五:总结
一、学习收获 通过设计各类功能模块,深入理解面向对象编程,掌握正则表达式、队列应用及调度算法逻辑。调试中学会用工具排查问题,提升问题解决能力;迭代作业锻炼心态,克服畏难情绪,建立编程信心
二、不足与改进 代码复杂度高、嵌套深,需优化结构,减少判断嵌套,运用设计原则重构。基础知识薄弱、缺乏系统思维,计划拆解目标学习,强化代码规范与测试习惯。
三、展望 编程是逻辑与心态的双重考验,未来将针对性提升短板,积累经验。建议课程增加分步引导与代码互评,助力高效学习。此次经历让我更坚定攻克难题的决心,持续成长。

posted @ 2025-04-20 22:30  242012yyy  阅读(56)  评论(0)    收藏  举报