一个不愿透露姓名的网友的博客

真香


  • 首页

  • 归档

输入输出系统/概述

发表于 2020-05-18

概述

1.输入输出的发展

  1. 早期
    • 分散连接
    • CPU和I/O设备串行工作,程序查询方式。
  2. 接口模块和DMA阶段
    • 总线连接
    • CPU和I/O设备并行工作。1.中断方式。2.DMA方式
  3. 具有通道结构的阶段
  4. 具有I/O处理机阶段

I/O逐渐从CPU中独立出来

2.输入输出系统组成

1.I/O软件

  1. I/O指令 CPU指令的一部分
    操作码:标识I/O指令
    命令码:相当于普通指令的操作码
    设备码:I/O设备编码(地址)
操作码 命令码 设备码
  1. 通道指令 通道自身指令
    • 三个参数
      1. 数组的首地址
      2. 字数
      3. 操作命令

        I/O硬件

  • 设备通过I/O接口连接在总线上和主机完成信息交换

通道方式:

  • 设备连接设备控制器连接子通道连接通道

    3.I/O设备和主机的联系方式

    联系->得知I/O设备的地址->编址

    1.I/O设备的编址方式

    1. 统一编址
    用取数,存数指令
    2.不统一编址
    有专门的I/O指令

    2.设备选址

    用设备选择电路识别是否被选中

    3.传送方式

    串行、并行

    4.联络方式

  1. 立即响应
  2. 异步工作采用应答方式
    • 并行
    • 并行
  3. 同步工作采用同步时标

    5.I/O设备和主机的连接方式

  4. 辐射性连接
    • 每台设备都有一套控制线路和一组信号线
    • 不利于增删设备
  5. 总线连接
    • 便于增删设备

      4.I/O设备与主机信息传送的控制方式

  • 程序查询方式
    85
  • 程序中断方式
    • I/O设备准备数据时,CPU不进行查询
    • I/O设备与主机进行信息交换时,CPU暂停现行程序
    • 没有踏步现象,中断现行程序
    • CPU和I/O部分并行工作

86

  • DMA方式
    • 主存和I/O设备中有一条直接的数据通道
    • 周期窃取(周期挪用)
    • 不中断现行程序

      三种方式比较

      87

      外部设备(I/O设备)

概述

主机<->I/O接口<->(外部设备)设备控制器<->光、电、磁部分(外部设备)

  • 外部设备
    • 人机交互设备
    • 计算机信息存储设备
    • 机-机之间通信设备
  • 输入设备
    • 键盘
      • 编码键盘法
    • 鼠标
    • 触摸屏
  • 输出设备
    • 显示器
      • 字符显示
      • 图形显示(主观画图)
      • 图像显示
    • 打印机
  • 其他
  • 多媒体技术

    I/O接口

    概述

    接口功能和组成

    1.总线连接方式的I/O接口电路

    88

    2.接口的功能和组成

    |功能|组成|
    |—-|—-|
    |选址功能|设备选择电路|
    |传送命令功能|命令寄存器、命令译码器|
    |传送数据功能|数据缓冲寄存器|
    |反映设备状态功能|设备状态标记|

    3.I/O基本接口组成

    89

    接口类型

    接口分类

    1.按数据传送方式
  • 并行接口
  • 串行串行
    2.按功能选择的灵活性分类
  • 可编程接口
  • 不可编程接口
    3.按照通用性分类
  • 通用接口
  • 专用接口
    4.按照数据传送的控制方式分类
  • 中断方式
  • DMA方式

    程序查询方式

    1.程序查询流程

    查询流程

    90

    2.程序流程

    91

    程序中断方式

    概念

    CPU在执行程序过程中,如果发生意外事件或者特殊事件,CPU要中断当前事件去处理特殊事件。通过执行中断服务程序的方式去处理特殊事件,处理结束后返回被中断程序的程序断点。

    I/O中断的产生

    92

    程序中断方式的接口电路

  1. 配置中断请求触发器和中断请求屏蔽器
  2. 排队器
  3. 中断向量地址形成部分

DMA(直接存储器访问)方式

发表于 2020-05-13
1
2
3
4
5
6
DMA占用内存时CPU不可占用
目录:
1.DMA方式特点
2.DMA接口的功能和组成
3.DMA的工作过程
4.DMA接口的类型

1.DMA方式特点

1.DMA和程序中断两种方式的数据通路

78
可跳过CPU节省CPU。把CPU冲数据交换中解放出来

2.DMA与主存交换数据的三种方式

1.停止CPU访问主存

  1. 控制简单
  2. CPU处于不工作状态或者维持现状
  3. 为充分发挥CPU对主存的利用率

    2.周期挪用(窃取)

  4. CPU访问时,DMA不可占用
  5. CPU未访问时,DMA可占用
  6. CPU和DMA同时申请时,占用分配给DMA(DMA连接都是高速I/O设备,不响应可能造成数据流失)

    3.DMA,CPU交替使用

    CPU工作周期C1,C2
    C1分配给CPU
    C2分配给DMA

    2.DMA接口的功能和组成

    1.DMA接口的功能

  7. 向CPU申请DMA传送
  8. 处理总线控制权的转交
  9. 管理系统总线,控制数据传送
  10. 确定数据传送的首地址和长度,修改传送过程中的地址和长度
  11. DMA传送结束,给出操作完成的信号

    2.DMA接口的组成

    AR(地址寄存器):得知传输地址
    WC(计数器):得知传输计数量(字数)
    BR(数据缓冲器):外部数据缓存
    DAR(设备地址寄存器):1.设备选择电路是使用,将设备地址保存。 2.对硬盘访问时,保存访问地址信息。
    84
    DREQ:device request设备请求
    DACK:device acknoledge设备应答
    设备对DMA设备逻辑控制发出DREQ,DMA设备逻辑控制对设备发出DACK。
    DMA对总线发出使用信号(HRQ)。
    总线对DMA发出应答信号(HLDA)。

    3.DMA的工作过程

    1.DMA传送过程

  12. 预处理
  13. 数据传送
  14. 后处理

    1.预处理

  15. 通知DMA控制逻辑的传送方向(输入输出)
  16. 设备地址——> DMA(DAR)
  17. 主存地址——> DMA(AR)
  18. 传送字数——> DMA(WC)

    2.数据传送

    79
    输入
    80
    输出
    81

    3.后处理

    由中断服务程序完成
  19. 校验送入主存的数据是否正确
  20. 是否继续使用DMA
  21. 检验传送过程是否正确,错则转诊断程序

    2.DMA接口和系统的连接方式

  22. 具有公共请求线的DMA请求
  23. 独立DMA请求

    3.DAM方式和程序中断方式的比较

    82

    4.DMA接口的类型

    1.选择型 2.多路型

    1.选择性

    物理上连接多个设备,逻辑上连接一个设备
    传送过程中只能又一个设备使用接口。

    2.多路型

    物理上连接多个设备,逻辑上连接多个设备
    传送过程中只有一个设备与传输,但是可以有多个设备同时进行数据准备

    3.多路型DMA接口的工作原理

    速度越高优先级越高
    83

主存储器

发表于 2020-05-04

2.半导体存储芯片简介

基本结构

地址线+数据线

片选线

  • 作用

    译码方式

    线选法


    所选中线工作其他不工作,线的排布很密集。
    对容量大的芯片不合适。

    重合法

    行列坐标
    适用存储矩阵

    小结

    假设20根地址线
    线选法:溢出1m条
    重合法则是:溢出2k条

    3.随机存取储存器(RAM)

    1.静态RAM(SRAM)

    2.动态RAM(DRAM)

    读操作时:
    预信号充电T4充电,VDD通过T4给读数据线充电。当选择读数据是读选择先被充电T2导通,如果,数据是1电容cg被充电,T1导通,数据线放电,此时数据线就是0.如果数据是0电容未充电,T1未导通,数据线不放电数据线读到的是
    写操作:
    如果写入的是1数据线通过T3向电容充电写入1,反之电容放电。
    写入信息相同读出相反。

    动态RAM刷新

    刷新与行地址有关

    集中刷新

    • 集中式刷新
  • 集中在某一时间内刷新
    • 有死区

      分散刷新

      写入后刷新
    • 增长读写周期
    • 芯片性能下降
    • 刷新太频繁

      异步刷新(分散和集中结合)

    • 每隔一段时间刷新一行
    • 刷新安排在译码阶段,不会产生死区

      3.对比

      1.

      4.只读存储器(ROM)

    • PROM一次性编程(采用熔丝)
    • EPROM多次性编程(紫外线全部擦除)
    • EEPROM多次性编程(多次擦除,局部擦出,电可擦写)
    • Flash Memory(闪速型存储器(U盘))

      5.存储器与CPU连接

      1.存储器容量扩展

      1.位扩展(增加存储字字长)

      用两个1k 4位的存储器构成一个1K 8位的存储器

      2.字扩展(增加储存字的数量)

      两个1K 8位的芯片组成一个2K 8 位的存储器

      3.同时扩展

      八个1K 4 位组成一个4K 8位的存储器

      2.存储器与CPU连接

      1.地址线的连接

      2.数据线的连接

      3.读/写命令线连接

      4.片选线的连接

      5.合理选择存储芯片

      5.其他 时序、负载

      6.存储器的校验

    • 受各种因素影响,容易出错。

编码最小距离:任意两组编码之间二进制数最少差异

  • 编码的纠错和检错能力和编码最小距离有关。
  • L-1=D+C(D>=C)
    • L 最小编码距离
    • D 检测错误的位数
    • C 纠错错误的位数

      汉明码组成

      添加检测位位数
      2^k>=n+k+1
      添加k位,分为k组
      检测位位置
      2^i(i=0,1,2,3……)(第1,2,3……组)
      检测数据(二进制第i位位1的数)
    • C1 检测(1,3,5,7,9……)
    • 第i小组独占第i位,同理第i,j小组独占第i,j位(二进制)

      汉明码的纠错过程

  • 形成新的检测为,其位数与增添的检测为有关
    检测位取值

    7.提高访存速度的措施

  • 采用高速器件
  • 采用cache-主存模式
  • 调整主存结构

    调整主存结构

    1.单体多字

  1. cpu为16位,内存为64位。cpu一次访问可读取4个机器字(cpu一次读取一组)
    缺点: 1. 写入时,如果只写入16位则会有48位被修改。
    2.取四条指令,如果第一条是跳转指令,而且跳出了后面三个字范围则只有一条指令有效。

    2.多体运行

    1.高位交叉 顺序编址
    将内存分为几个存储体。高位为存储体编号,后几位为存储体内编号。将多个存储体独立。
    地址:|体号|体内地址|
    缺点: 可能造成某一存储体很繁忙。(程序执行是顺序存放地址)
    2.低位交叉 各个体轮流编址
    低位位体号。
    地址:|体内地址|体号|
    特点:不改变存取周期情况下,增加带宽。

    3.高性能存储芯片

  • SDRAM(同步DRAM)
    • cpu无序等待
  • RDRAM
    • 解决存储宽带问题
  • 带cache的DRAM
    • 有利于猝发式读取

存储器

发表于 2020-04-22

概述

1.存储器分类

1.按照介质分类

  1. 半导体存储器(TTL,MOS)
  2. 磁表面存储器(磁头,载磁体)
  3. 磁性存储器(硬磁材料,环装原件)
  4. 光盘存储器(激光,激光材料)

    2.按照存取方式分类

  5. 存取时间与物理地址无关(随机访问)
    • 随机存储器(可读可写)
    • 只读存储器(只可读)
  6. 存取时间与物理地址有关(串行访问)
    • 顺序存取存储器(磁带)
    • 直接存取存储器(磁盘)
  7. 按在计算机中的作用
    • 主存储器
      • RAM(随机存储器)
        • 静态 RAM
        • 动态 RAM
      • ROM(只读存储器)
        • MROM
        • PROM
        • EPROM
        • EEPROM
    • flash Momery(比磁盘快,比主存储器慢)(比如:U盘)
      • 可作为硬盘
      • 可作为辅助存储器缓冲
    • 辅助存储器
      • 磁盘、磁带、光盘等
    • 高速缓冲存储器(cache)
      • 可作为cpu与主存之间的缓冲区(比主存快)

        2.存储器层次结构

        1.存储器三个主要特性关系

        单独一种存储器无法满足人们需求所以分为许多存储形成一个存储体

        2.缓存-主存层次和储存-辅存层次

        主存储器

        1.主存的基本组成

        2.主存与CPU之间的联系

        3.主存中储存单元地址的分配


        32位机1个字4字节16位则是2字节所以一个除4一个除2
        W=word

        4.主存技术指标

  8. 存储容量:主存 存放二进制代码的总位数
  9. 存储速度:
    • 存取时间
      存储器的 1.读出时间 2.访问时间 3.写入时间
    • 存取周期
      • 两次连续的独立的存储器操作所需最小间隔周期 (一次开始到另一次开始)
        • 读操作
        • 写操作
  10. 存储带宽 单位:位/秒

    高速缓冲存储器(cache)

    概述

    1.问题的提出

  • 解决cpu空等问题 cpu与主存(DRAM)的速度差异
  • 程序访问的局部性原理
    • 局部性原理是指CPU访问存储器时,无论是存取指令还是存取数据,所访问的存储单元都趋于聚集在一个较小的连续区域中。

      2.工作原理

  1. 主存与缓存的编址
  • cacha与主存之间数据交换单位为块
  • 块中包块在使用的指令与数据与相邻的指令与数据
  • 块分为:块内地址,块号
  • cacha还有一个标记用来记录主存的块的块号
  • 块内地址(块内偏移地址)他的位数决定块的大小
  • 主存块内地址与cacha中块内地址址相同。
  1. 命中与非命中
  2. cacha的命中率
  • cpu所需要的信息在cacha中比例
  • 与块长与容量有关
  • 一般4-8字
  • 块长与一个存储周期中主存中取出信息长度
  1. cache-主存系统效率

    3.cache基本结构


    映射结构:主存的块可放到cacha中哪个块
    变换机构:主存中块在cacha中哪个块查找
    替换机构:调用替换算法,哪个块冲cacha跳出

    4.cache的读写操作

    读

    写

    优点
    写直法:cache和主存内容一直一致
    写回法:不会造成频繁的主存与cache的交互
    缺点
    写直法:可能会cpu对同一个单元的反复写,可能造成频繁的主存与cache的交互
    学会法:保证不了cache与主存一直一致,多处理器有多个副本无法保证副本的一致性

    5.cache改进

  • 增加cache级数
    • 片载(片内)cache
    • 片外cache
  • 统一缓存和分立缓存
    • 指令cache
    • 数据cache

      cache主存地址映射

      1.直接映射

  • cache利用效率可能很低,且容易发生冲突
  • 每个缓存块i可以和多个主存块对应
  • 每个主存块j只能和一个缓存块对应
  • i = j mod C
  • 效率高

    2.全相联映射

  • 每个内存块可以映射任意一个缓存块中
  • 效率低
  • 利用率高

    3.组相联映射

  • 全相联映射和直接映射的折中
  • 缓存中组数和主存中区数中的块数相同
  • 某一主存块j按照模Q映射到i组中任意一块

    替换算法

    1.先进先出算法(FIFO)

  • 先进先出
  • 并不是很合理(例子:床头书柜)。

    2.近期最少使用算法(LRU)

  • 最近时间段使用最少的或者(之后使用需要很长时间)替换出去

    3.随机淘汰算法(RAND)

  • 随机选择一个用户页替换出

    4.最佳替换算法

  • 替换到最晚到来的用户页

    *小结

  • 直接映射:某一主存块只能映射到一个缓存块
    • cache利用率低,不灵活
  • 全相联映射:某一主存块能映射到任意缓存块中
    • 成本高,cache利用率低
  • 组相联映射:某一主存块只能映射到某一缓存组中的任意一块
    • 全相连映射和直接映射的折中

      辅助存储器

      1.概述

      特点

  • 不能直接和cpu交换信息

    磁表面储存器的技术指标

    2.磁记录原理和记录方式

    写
    改变线圈电流方向转换磁极对磁载体进行磁化,写入0或者1
    读
    磁层运动,磁通切割磁感线产生电流变化

    3.硬磁盘储存器

    1.类型

  1. 固定磁头和移动磁头
  2. 可换盘和固定盘

    2.结构

    主机<->磁盘控制器<->磁盘驱动器<->盘片

    4.软磁盘储存器

  • 硬盘速度高,软盘速度低
  • 硬盘有固定、活动磁头,软盘只有活动磁头
  • 硬盘磁头悬浮在硬盘表面,软盘与磁头接触
  • 硬盘多为固定盘,盘组大部分不可更换,软盘可更换
  • 硬盘价格高,软磁盘价格低
  • 硬盘环境要求苛刻,软盘不是很苛刻

    5.光盘储存器

  • 采用光储存技术,利用激光读入写入
    • 第一代:非磁介质,不可擦写
    • 第二代:磁介质,可擦写
  • 储存原理
    • 只读型(热作用,化学或者物理方法)
    • 只写一次型(热作用,化学或者物理方法)
    • 可擦可写(热磁效应)

计网第一章

发表于 2020-03-20





互联网特点:连通性共享性
互联网具有虚拟的特点,无法具体知道对方是谁也无法知道具体的位置。





1.互联网形成

第一阶段:单个网络APPANET 向互联网的发展过程

  • 1983年 TCP/IP 协议成为 APPANET的标准协议,任何使用TCP/IP协议的计算机都可以使用互联网相互通信
  • 因此人们把1983年当做互联网诞生的时间
  • 1990 APPANET 关闭
    互联网为专有名字与互连网不同
    不同

    第二阶段:建成三级架构的互联网

  • 主干网
  • 地区网
  • 校园网(企业网)
    第三阶段:逐渐形成 多层ISP结构互联网
  • ISP (Internet Service Provider)
  • 任何机构和个人只要向ISP交纳规定费用,便可从ISP获取所需IP使用权,并将该ISP接入互联网。
  • 根据提供服务面积大小及IP数量多少,分为 1. 主干ISP 2.地区ISP 3.个人ISP


    成为互联网正式标准需要经过的阶段

    所有互联网标准都以RFC形式在互联网上发表

    最开始需经过三个阶段

  • 互联网草案——有效期只有六个月,此时还 不是 RFC文档
  • 建议标准——这个时期 开始成为 RFC文档
  • 互联网标准——达到正式标准后,每个标准会分配到一个标准号STDXXX。一个标准可以和多个RFC文档关联。

现简化为两个过程:建议标准和花联网标准。

除了建议标准和互联网标准两种RFC文档外,还有历史的、提供信息的、实验的RFC。
关系如下
关系图





并从工作方式上康,互联网分为两个部分。

  • 互联网的边缘部分:由主机构成。这部分由用户直接使用,用来通信和资源共享。
  • 互联网的核心部分:由大量的网络和连接这些网络的路由器组成。这部分是为了向边缘部分提供服务。(提供连通性和交换)


    互联网边缘部分,也就是连接在互联网上的所有主机又称为 端系统。
    主机在功能上可以有很大的差别。


    主机A与主机B通信:运行在主机A上的一个程序与运行在主机B上的一个程序进行通信。


    通信方式通常可以分为两大类
  • C/S clien / server 客户对服务器通信。
  • P2P peer to peer对等通信。

    客户-服务器方式

    客户和服务器都是指通信过程中所涉及的两个应用进程。
    客户-服务器是进程之间服务和被服务之间的关系。
    客户是服务请求方,服务器是服务提供方

客户软件的特点:

  • 被用户调用后 ,在打算通信前主动向远地服务器发起通信(发送请求)。因此要知道服务器程序的地址
  • 不需要特殊的硬件系统和很复杂的操作系统。

    服务器软件的特点:

    p2p方式

  • 没有服务方和被服务方的区别。
  • 只要两个主机都下载了对等连接软件(p2p软件)就可以进行对等的、平等的通信。
  • 双方都可以储存在对方硬盘里的 共享文档。

    对等连接的特点

  • 本质上还是C/S 连接方式只是对等连接中的每一个主机既是服务器又是客户。
  • 支持大量(上百万)对等用户同时工作。

互联网核心部分

  • 最复杂
  • 向边缘部分提供连通性
  • 起特殊作用的是路由器。路由器:实现分组交换的关键构建。作用是实现分组转发,这也是网络核心部分的 最重要功能。

交换

1.电路交换
2.分组交换
3.报文交换
互联网核心部分采用了分组交换。

电路交换

N部电话机两两相连需要N(N-1)/2,和交换机的数量的平方成正比。
*电话机很多是就要用交换机来完成连接全网的交换工作。采用的交换是电路交换。

交换:转换,从通信角度康,就是动态分配传输线路的资源。

电路交换特点

  • 面向连接
  • 分为是三个阶段
    • 建立连接
    • 通信
    • 释放连接
  • 计算机数据具有突发性
  • 线路利用率极低(传送数据的时间往往只不到10%甚至不到1%)

    分组交换特点

  • 采用储存转发技术
  • 把较长的报文,划分为较短的、固定长度的报文
  • 每一段数据前加上首部构成分组
  • 以分组为基本单元在网络中传输

    分组

  • 每一个分组的首部都有地址等信息。
  • 每个分组在互联网中有独立的传输路径

    路由器

  • 路由器输入与输出端口间没有直接连线。
  • 处理分组过程
    • 把分组放到缓存区,暂时储存
    • 查找转发表,找到某个目的地址应从哪个端口发出
    • 把分组转到适当的端口发出

分组转发好处

  • 高效:动态分配传出宽带,对通信链路逐段占用
  • 灵活:为每个分组寻找最适合转发路由
  • 迅速:可不建立连接
  • 可靠:保证可靠性的网络协议;分布式多路由的分组交换网,使网络有很好的生存性。

带来问题

  • 必须排队,所以有时延
  • 有首部,所以造成一定浪费

计算机网络

定义

并未有很好的定义

计算机网络主要是由一些通用的、可编程的硬件互连而成的,而这些硬件并非专门用来实现某一特定目的(例如,传送数据或视频信号)。这些可编程的硬件能够用来传送多种不同类型的数据,并能支持广泛的和日益增长的应用

区分





性能指标

速率,带宽,吞吐率,时延,时延带宽积,往返时间RTT,利用率。

带宽

在计算机网络中,带宽用来表示网络中某通道传送数据的能力。表示在单位时间内网络中的某信道所能通过的“最高数据率”。单位是 bit/s,即 “比特每秒”

吞吐量受网络的带宽或网络的额定速率的限制

时延带宽积=传播时延*带宽

利用率

  • 信道利用率指出某信道有百分之几的时间是被利用的(有数据通过)。
  • 完全空闲的信道的利用率是零。
  • 网络利用率则是全网络的信道利用率的加权平均值。
  • 信道利用率并非越高越好。当某信道的利用率增大时,该信道引起的时延也就迅速增加。

若令 D0 表示网络空闲时的时延,D 表示网络当前的时延,则在适当的假定条件下,可以用下面的简单公式表示 D 和 D0 之间的关系
D=D0/(1-U)

网络协议是计算机网络的不可缺少的组成部分

TCP/IP

  • 应用层
  • 运输层
  • 网际层
  • 网络接口层
    五层协议
  • 应用层
  • 运输层
  • 网络层
  • 网络链路层
  • 物理层

二分图&匈牙利算法

发表于 2019-10-15

author:tc
勤劳的tc来了首先是二分图
他主要是有两个顶点集,然后顶点之间不能连接起来。?。。
怎么判断它是二分图?。。
先将一个一个点标记为1(或者0)然后与它连接起来的为标记的的就标记为0(或者1),如果该点已经标记,则判断他是否和顶点的值相同,相同则不为二分图,反之则是是。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
bool is_two() {
queue<int> que;
que.push(1);
int from;
visit[1]=1;
while(!que.empty()) {
from=que.front();
que.pop();
int i=1;
for(i; i<=n; i++) {
if(map[from][i]) {
if(!visit[i]) {
que.push(i);
visit[i]=(visit[from]&1)+1;
} else if(visit[i]==visit[from]) {
return false;
}
}
}
}
return true;
}
```
匈牙利算法主要是解决是二分图匹配问题。
一个顶点可以与多个结点相连。如果一个顶点只连接一个顶点求最多可以连接多少。
假如 a可以和c,d,e,f相连,h可以和c,d,m,n, z可以和c,d,k相连。
首先先匹配a和c。
第二步是匹配h,h不能喝c匹配,但是h并不想换人,所以就返回去看a能不能换a没办法只能换一个换到了d,h匹配到了c。最后就是z了,他也想匹配c,可是他也不想换,只能h换了,h换成了d可是d又和a匹配了,h也不想换之后a换了,a最后换成了e。最后a,h,z都匹配好了。
当然这个换人的过程是用递归实现的。

bool find(int x) {
int j=1;
for(; j<=n; j++) {
if(map[x][j]&&!visit[j]) {
visit[j]=true;
if(!match[j]||find(match[j])) {
match[j]=x;
return true;
}
}
}
return false;
}

1
2
3
4
5
6
7
8
9
10
以下是题目:  
[hdu2444](http://acm.hdu.edu.cn/showproblem.php?pid=2444)
这道题先要判断是否为二分图,否的话输出-1







include

include

include

using namespace std;

//bool find()

int map[205][205];

int match[205];
int visit[205];

int n,m;

bool find(int x) {
int j=1;
for(; j<=n; j++) {
if(map[x][j]&&!visit[j]) {
visit[j]=true;
if(!match[j]||find(match[j])) {
match[j]=x;
return true;
}
}
}
return false;
}

bool is_two() {
queue que;
que.push(1);
int from;
visit[1]=1;
while(!que.empty()) {
from=que.front();
que.pop();
int i=1;
for(i; i<=n; i++) {
if(map[from][i]) {
if(!visit[i]) {
que.push(i);
visit[i]=(visit[from]&1)+1;
} else if(visit[i]==visit[from]) {
return false;
}
}
}
}
return true;
}

int main() {
cin.tie(NULL);
cout.tie(NULL);
ios::sync_with_stdio(false);
while(cin>>n>>m) {
memset(map,0,sizeof map);
memset(match,0,sizeof match);
memset(visit,0,sizeof visit);
int i=0,one,two;
for(; i>one>>two;
map[one][two]=1;
map[two][one]=1;
}
int ans=0;
if(!is_two()||n==1) {
cout<<”No”<<endl;
continue;
}
for(int i=1; i<=n; i++) {
memset(visit,0,sizeof visit);
ans+=find(i);
}
cout<<ans/2<<endl;
}
return 0;
}
```

树形dp&&一些其他的很杂的东西

发表于 2019-09-24

Oh,Oh勤劳的tc来了 。。
讲道理 很久没写了,也并不是很勤劳(小声bb)先是树形dp
就像他的名字这个dp是对像树一样的数据进行dp一般都是图,毕竟图你把每个点连起来就像树一样?!
说是dp其实我觉得像dfs+dp。
因为他的数据和树一样,所以普通的dp是完成不了的。首先他的一个节点上有很多个儿子结点,儿子节点上又有很多结点。所以这里用了dfs从他的叶子结点dp从他的叶子结点就开始判断最佳路径。
下面是题目
hdu 1011
首先他一个士兵可以打败20个怪兽意思,但是即使只有一个怪兽也要用1个士兵。所以这里判断士兵用量就是(bugs+19)/20 。然后dp的部分,先用一个数组二维的int型value[u][v]来记录他的路径。 u就是当前所在层数,然后v就是当前层数所有的士兵数,然后他是从后往前dp的所以他的dp转移方程就是
value[u][v]=max(value[u][v],value[u][v-j]+value[next][j]);这里的next就是和当前节点相连的一个节点然后他在第n层的最大brain获取量就是第u层留下v-j的brain获取量和next层花费j士兵是获取的brain量
code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
#include<iostream>
#include<unordered_map>
#include<algorithm>
#include<cmath>
#include<queue>
#include<cstring>
#include<vector>
#define fastc cin.tie(NULL);
#define fasto cout.tie(NULL);
#define fasts ios::sync_with_stdio(false);
#define END return 0;
#include<iomanip>

using namespace std;
//char num[1000];

int value[101][101];//记录值进行dp
int visit[101];//看是否访问过,避免重复查找。
int rec[101][101];//记录地图
typedef pair<int,int> P;//储存bugs和brains
P pa[101];

int n,m;


void dp(int u) {
visit[u]=1;
int cost=(pa[u].first+19)/20;
for(int i=m; i>=cost; i--) {
value[u][i]=pa[u].second;//在第u层花费了cost个士兵都可以获得所有的brain
}
for(int i=1; i<=n; i++) {
if(rec[u][i] && !visit[i]) {
dp(i);
for(int j=m; j>=cost; j--) {
int rest=j-cost;
for(int k=1; k<=rest; k++) {
value[u][j]=max(value[u][j],value[i][k]+value[u][j-k]);
}
}
}
}
}

void prin() {
for(int i=0; i<=n; i++) {
for(int j=0; j<=m; j++) {
cout<<value[i][j]<<" ";
}
cout<<endl;
}
//cout<<endl;
}


int main() {
fastc fasto fasts
while(cin>>n>>m) {
if(n==m&&n==-1) break;
memset(value,0,sizeof(value));
memset(visit,0,sizeof(visit));
memset(pa,0,sizeof(pa));
memset(rec,0,sizeof(rec));
int i=1;
for(i; i<=n; i++) {
cin>>pa[i].first>>pa[i].second;
}
int one,two;
for(i=1; i<n; i++) {
cin>>one>>two;
rec[one][two]=1;
rec[two][one]=1;
}
dp(1);
prin();
cout<<value[1][m]<<endl;
}
END
}

题目:
dfs剪枝
hdu1010
这题是已经规定了步数
|0|1|0|1|0|1|
—|:—:|—:|—:|—:|—:|
|1|0|1|0|1|0|
|0|1|0|1|0|1|
|1|0|1|0|1|0|
|0|1|0|1|0|1|
|1|0|1|0|1|0|
|0|1|0|1|0|1|
|1|0|1|0|1|0|
|0|1|0|1|0|1|
|1|0|1|0|1|0|
|0|1|0|1|0|1|
可以知道从1走到0的步数一定是奇数
这里是最重要的一个剪枝,只有当起点的横纵坐标的奇偶性相同时,步数必须是奇数,反之则是偶数。
数论小知识
题目:
hdu1013
Digtial Roots=(sum-1)%9+1

吴天赐2019暑假答辩/周任务上传下载

发表于 2019-09-10

eeee,因为一些原因我这里只有后台。
主要的操作只有一些基础的增删改查,然后就是上传下载还有就是删除文件。
路径我是写在了yml中然后通过@ConfigurationProperties注解建立一个路径的properties的映射叫filePath,之后再使用路径。
api的接口是用swagger写的,但是我这里用的方法不对,不过swagger还是很好用的不过他要到几个依赖

1
2
3
4
5
6
7
8
9
10
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.5.0</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.5.0</version>
</dependency>

还有就是这两个依赖的版本最好一样,不然会出现bug,接口文档通过注解,然后再通过浏览器获取网址
网址一般都是:http://localhost:8080/swagger-ui.html
然后还可以在上面测试接口。
我这回用的是前后端分离,通过controller返回的是一个Result的模板类,其中有前端向后台请求的数据和返回的关于请求的信息。
上传的主要逻辑是先获取上传文件,然后判断是否是压缩文件,不是的话就返回用户他的文件信息,反之继续。文件的路径名用filePath中的路径当做母路径,母路径上再加上他的文件id、时间、一个随机数作为他的子路径。然后再用file.transferTo进行上传。之后再更新他的任务的信息,成员的信息,和提交信息。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
package com.ctgu.upndo.controller;


import com.ctgu.upndo.pojo.Member;
import com.ctgu.upndo.pojo.Submit;
import com.ctgu.upndo.pojo.Task;
import com.ctgu.upndo.propeties.propeties;
import com.ctgu.upndo.service.SaveAndFlushService;
import com.ctgu.upndo.service.SearchService;
import com.ctgu.upndo.utils.CodeEnum;
import com.ctgu.upndo.utils.GetWayRan;
import com.ctgu.upndo.utils.Result;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import java.awt.print.Pageable;
import java.io.File;

@RestController
@RequestMapping("/upload")
public class UploadController {
@Autowired
propeties filepath;
@Autowired
SearchService searchService;
@Autowired
SaveAndFlushService saveAndFlushService;
@ApiOperation(value="上传")
@ApiImplicitParams({
@ApiImplicitParam(name="file",value="前端文件,只有一个"),
@ApiImplicitParam(name="submit",value = "提交详细Submit对象")
})
@RequestMapping("/one")
public Result<Integer> upload( @RequestParam("file") MultipartFile file, @RequestParam("submit") Submit submit) {
Result<Integer> res = new Result<>();
try {
if (file.isEmpty()) {
res.setResult("文件是空的啊..");
return res;
}
String fileName = file.getOriginalFilename();
String suffixName = fileName.substring(fileName.lastIndexOf("."));
if (suffixName != "zip" && suffixName!="rar") {
res.setResult("30008","文件必须是zip和rar的啊,你的怎么是" + suffixName + "的啊");
return res;
}
Result<Member> rm = searchService.findMemberByTidAndUid(submit.getTid(), submit.getSid());
if(rm.getData()==null){
res.setResult(CodeEnum.UPLOAD_ERROR);
return res;
}
Member member=rm.getData();
Integer times = rm.getData().getTimes();
times++;
Integer ta = submit.getTid();
member.setTimes(times);
String ran= GetWayRan.getUpLoadRandom();
String path = filepath.getUpload_path()+ta.toString()+File.separator+ran+suffixName;
submit.setWay(path);
member.setLast(path);
File fi = new File(path);
if (!fi.getParentFile().exists()) {
fi.getParentFile().mkdir();
}
if (times == 1) {
Result<Task> rt = searchService.findTaskByTid(submit.getTid());
Task task=rt.getData();
Integer number = task.getFinish();
number++;
task.setFinish(number);
saveAndFlushService.SaveAndFlushTask(task);
}
file.transferTo(fi);
saveAndFlushService.SaveSubmit(submit);
saveAndFlushService.SaveAndFlushMember(member);
} catch (Exception e) {
res.setResult(CodeEnum.UPLOAD_ERROR);
}
res.setResult(CodeEnum.UPDATE_SUCCESS);
return res;
}

}

然后是下载,下载分为 两种学生下载,和管理员下载。学生下载需要前端传来判断信息。然后通过路径通过缓冲流进行下载。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
package com.ctgu.upndo.controller;

import com.ctgu.upndo.pojo.Submit;
import com.ctgu.upndo.service.SearchService;
import com.ctgu.upndo.utils.CodeEnum;
import com.ctgu.upndo.utils.GetNumber;
import com.ctgu.upndo.utils.Result;
import com.ctgu.upndo.utils.ToNumber;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.List;

@RestController
@RequestMapping("/download")
public class DownloadController {

@Autowired
SearchService searchService;
@ApiOperation(value="下载")
@ApiImplicitParam(name="list",value="String对象,下载项目序号")
@RequestMapping(value = "student")
public Result<Integer> upload(HttpServletRequest request, HttpServletResponse response,@RequestParam(value = "path") String path,@RequestParam(value = "judge") String judge){
Result<Integer> res=new Result<>();
Integer flag= ToNumber.getNumber(judge);
if(flag==0){
res.setResult("30013","未在时限内,不可下载");
}
res.setResult(CodeEnum.DOWNLOAD_SUCCESS);
String status=null;
String fileName=new String();
BufferedInputStream bis = null;
try{
File file=new File(path);
if(!file.exists()){
res.setResult("30012","文件为空");
return res;
}
fileName=file.getName();
response.setContentType("application/force-download");// 设置强制下载不打开
response.addHeader("Content-Disposition", "attachment;fileName=" + fileName);// 设置文件名
byte[] buffer=new byte[1024];
bis=new BufferedInputStream(new FileInputStream(file));
OutputStream os=response.getOutputStream();
int number=bis.read(buffer);
while(number!=-1){
os.write(buffer,0,number);
number=bis.read(buffer);
}
}catch(Exception e){
res.setResult(CodeEnum.DOWNLOAD_ERROR);
}

return res;
}

}

管理员的复杂一点,前端传来字符串然后我进行处理得出他的需要下载的id。然后将文件打包成zip放在客户端上进行下载。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
package com.ctgu.upndo.controller;


import com.ctgu.upndo.mapper.MemberMapper;
import com.ctgu.upndo.mapper.TaskMapper;
import com.ctgu.upndo.pojo.Member;
import com.ctgu.upndo.pojo.Task;
import com.ctgu.upndo.utils.CodeEnum;
import com.ctgu.upndo.utils.GetNumber;
import com.ctgu.upndo.utils.Result;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.HttpURLConnection;
import java.util.ArrayList;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

@RequestMapping(value = "/downloads")
public class Download {
@Autowired
MemberMapper memberMapper;
@Autowired
TaskMapper taskMapper;

public Result<Integer> downloads(HttpServletResponse res, String list) throws IOException {
Result<Integer> result = new Result<>();
List<Integer> numbers = GetNumber.getnumber(list);
int len = numbers.size();
List<String> filePaths = new ArrayList<>();
Member member = new Member();
//String way = new String();
for (int i = 0; i < len; i++) {
member = memberMapper.findMemberById(numbers.get(i));
filePaths.add(member.getLast());
}
Task task = taskMapper.findTaskById(member.getTid());
String name = task.getTitle();
result.setResult(CodeEnum.SCCESS);
try {
File file = new File(member.getLast());
String zipBasePath = file.getAbsolutePath();
String zipName = name + ".zip";
String zipFilePath = zipBasePath + File.separator + zipName;

res.setCharacterEncoding("UTF-8"); //设置编码字符
res.setContentType("application/force-download;charset=UTF-8"); //设置下载内容类型
OutputStream out = res.getOutputStream(); //创建页面返回方式为输出流,会自动弹出下载框


File zip = new File(zipFilePath);
if (!zip.exists()) {
zip.createNewFile();
}
//创建zip文件输出流
ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(zip));
this.zipFile(zipBasePath, zipName, zipFilePath, filePaths, zos);
zos.close();
res.setHeader("Content-disposition", "attachment;filename=" + zipName);//设置下载的压缩文件名称

//将打包后的文件写到客户端,输出的方法同上,使用缓冲流输出
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(zipFilePath));
byte[] buff = new byte[bis.available()];
bis.read(buff);
bis.close();
out.write(buff);//输出数据文件
out.flush();//释放缓存
out.close();//关闭输出流
} catch (Exception e) {
result.setResult(CodeEnum.DOWNLOAD_ERROR);
}
return result;
}

private String zipFile(String zipBasePath, String zipName, String zipFilePath, List<String> filePaths, ZipOutputStream zos) throws IOException {

//循环读取文件路径集合,获取每一个文件的路径
for (String filePath : filePaths) {
File inputFile = new File(filePath); //根据文件路径创建文件
if (inputFile.exists()) { //判断文件是否存在

//创建输入流读取文件
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(inputFile));

//将文件写入zip内,即将文件进行打包
zos.putNextEntry(new ZipEntry(inputFile.getName()));

//写入文件的方法
int size = 0;
byte[] buffer = new byte[1024]; //设置读取数据缓存大小
while ((size = bis.read(buffer)) > 0) {
zos.write(buffer, 0, size);
}
//关闭输入输出流
zos.closeEntry();
bis.close();
}
}
return null;
}
}

最后就是我的工具类,里面都是我对字符串的处理的一些类和我的Result类和CodeEnum。
utils
最后就是觉得自己对jpa了解了更多了吧。然后就是吸取了很多教训。虽然做的很不好不过感觉收获还是蛮大的。

马拉车算法 Manacher‘sAlgorithm Author:tc

发表于 2019-07-26

勤劳的tc又来了这回是马拉车。讲道理我应该先学kmp的。算了kmp之后在学。马拉车算法是求最大回文串的。受用面很窄。
ok接下来就是algorithm time
第一步是先将原本的字符串初始化。将每个字符用一个符号包裹,一般是#。
在这个时候字符串无论如何就都是偶数了。有什么用呢,举个例子。我们从下标为1开始。
 #1#2#2#1#
看这里中心位置是 一个#号然后他的下标是index=5,然后这个字符串的半径是r=5,然后原字符串就是 1221,可以看出这回字符串是从0(index-r) 开始 后四位(r-1)。这里是他最神奇的地方。也让他简便了很多。
我们一般字符串都是从下标0开始的所以我们在他前面加一个字符串里没有的字符一般,我取的是$。
当然这个算法不只这么一点。首先他有一个数组p[i],记录他每个位置的回文串的大小,然后又一个变量mx记录回文串可以到达的最右边下标,他还有个变量id记录该字符串的下标。

1
2
3
4
5
6
这里在开始匹配前记录回文串半径最小值。  
当```mx>i```
很容易我们可以得到``` k=id*2-i```是i 关于id的对称点。而以id为中心
mx-id为半径的字符串是对称的,所以当p[k]的边界在id的边界之内,以下标为i的字符串的半径为p[k]的字符串一定是回文串。而当p[k] 大于id的边界的时候就不能保证对称性了,所以这里就取mx-i。
当mx < i 这里我们就不能确定对称性了,所以直接取1.
以下是代码:

include

include

using namespace std;
string name,lo;
string lon(){
lo=”$”;
int i=0;
while(name.size()>i){
lo+=”#”;
lo+=name[i];
i++;
}
lo+=”#”;
int si=0,index=0;
vector p(lo.size(),0);
i=0;
int mx=0;
int id=0;
int len=lo.size();
for(i;ii? min(p[id*2-i],mx-i):1;
while(lo[i-p[i]]==lo[i+p[i]]) p[i]++;
if(mxsi){
index=i;
si=p[i];
}
}
cout<<name<<” “<<endl;
return name.substr((index-si)/2,si-1);
}

int main(){
name=”11123123312123311”;
cout<<lon();
return 0;
}
```

offsetof 宏定义

发表于 2019-06-11

offsetof

这里求得是结构体ST他的某一成员的的地址偏移量。就是MEMBER这个成员地址比他的结构体多了多少。
首先

1
2
int *p=(int *)0 ;
cout<<p;

他的结果是0,他这里虽然有强制转换,但是赋值的时候他赋0,p的值就是0,不管怎么转换0就是0。
所以从内层开始,他这里将0的类型转换成了ST类型,然后取他的成员MEMBER,最后在外面取了地址,(size_t就相当于unsigned int)。
成员的地址相当于首地址+偏移量,这里他的首地址为0了,所以直接取的地址就是偏移量了。

<123>

29 日志
© 2021 无敌 .2.0
由 Hexo 强力驱动
|
主题 — NexT.Muse v5.1.4