《数据结构与算法分析》课件第8章_第1页
《数据结构与算法分析》课件第8章_第2页
《数据结构与算法分析》课件第8章_第3页
《数据结构与算法分析》课件第8章_第4页
《数据结构与算法分析》课件第8章_第5页
已阅读5页,还剩76页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第8章缩小规模算法8.1分治与递归算法8.2动态规划8.3贪心算法

8.1分治与递归算法

8.1.1递归算法设计

一个直接或间接调用自身的算法称为递归算法。一个函数是用自身给出定义的函数称为递归函数。在计算机算法设计中,使用递归策略往往使算法的描述和函数的定义简洁,且易于理解。

1.排列问题

设R={r1,r2,…,rn}是要进行排列的n个元素,Ri=

R-{ri}。设集合X中元素的全排列记为Perm(X);(ri)Perm(X)表示在全排列Perm(X)的每一个排列前加上前缀ri得到的排列。R的全排列可递归定义为

(1)当n=1时,Perm(R)=(r1),r1是集合R中的唯一元素。

(2)当n>1时,Perm(R)由(r1)Perm(R1),(r2)Perm(R2),

…,(rn)Perm(Rn)构成。

2.整数划分问题

将一个正整数n表示为一系列正整数之和:

n=n1+n2+ … +nk,

其中,n1≥n2≥…≥nk≥1,k≥1。该表示称为n的一个划分;不同划分的个数称为划分数,记为p(n)。例如,6有如下11种不同的划分:在正整数n的所有不同划分中,将最大加数n1不大于m的划分个数记为q(n,m),则可以建立如下的递归关系:

(1) q(n,1)=1,n≥1;

当最大加数n1不大于1时,任何正整数只有一种划分形式:n=1+1+ … +1。

(2) q(n,m)=q(n,n),m≥n;

最大加数n1不能大于n,因此q(1,m)=1。

(3) q(n,n)=1+q(n,n-1);

正整数n的划分,由n1=n的划分和n1≤n-1的划分组成。

(4) q(n,m)=q(n,m-1)+q(n-m,m),n>m>1;

正整数n的最大加数n1不大于m的划分,由n1=m的划分和n1≤m-1的划分组成。以上关系实际上给出了计算q(n,m)的递归计算式:

(8-1)

据此可得到计算q(n,m)的递归函数。8.1.2分治算法设计

分治算法的基本思想是将一个规模为n的问题分解为k个规模较小的子问题,这些子问题相互独立且与原问题相同。递归地解这些子问题,然后将这些子问题的解合并,就得到了原问题的解。一般算法设计模式如下:

1.二分搜索技术

二分搜索技术是查找一个已排好序的表的最好方法,其查找效率较高。

给定一个排好序的n个元素R[0]~R[n-1],现要在这n个元素中找出一个特定元素x。例如,已知数组元素的有序序列为:5,10,19,21,31,37,42,48,50,55,现要查找x分别为19及66的元素,其查找过程如下:由于low>high,因此说明查找失败。

在二分搜索算法中,每进行一次比较,数组都缩小一半,从1/2,1/4,1/8,…,在第i次比较时,最多只剩下

n/2i

个记录。最坏的情况是到最后只剩下一个记录,即n/2i=1,所以i=lbn,即最坏情况下比较次数的复杂度是O(lbn)。

二分搜索中查找到每一个记录的比较次数可通过二叉树来描述:用当前查找区间中间位置上的记录作为根,左子表和右子表中的记录分别作为根的左子树和右子树,由此得到的二叉树称为折半查找判定树;树中结点内的数字表示该结点在有序表中的位置。例如,对长度为11的表进行折半查找时,其判定树如图8-1所示。图8-1具有11个结点的折半查找判定树可见,若查找的结点是表中第6个记录,需要一次比较;若查找的是表中第3个或第9个记录,需要两次比较;若查找的是表中第11个记录,需要三次比较,由此看出,折半查找的过程恰好是走了一条从根到被查找结点的路径,关键字进行比较的次数即为被查找结点在树中的层数。因此,折半查找成功时进行的比较次数最多不超过树的深度。那么,二分搜索的平均查找长度是多少呢?为方便起见,不妨设结点总数n=2h-1,则判定树的深度为h=lb(n+1)

的满二叉树,在等概率的条件下,折半查找的平均查找长

度为

(8-2)

当结点总数n很大时,ASLbin

lb(n+1)-1。

2.归并排序

归并排序(MergeSort)是将两个或两个以上的有序表合成一个新的有序表。归并排序算法是使用分治策略实现对n个元素进行排序的算法。其基本思想是:当n=1时,终止排序;否则将待排序的元素分成大致相同的两个子集合,分别对两个子集合进行归并排序。最终将排好序的子集合合并成所要求的排序结果。例如,对于一组待排序的记录,其关键字分别为:47,33,61,82,72,11,25,47

,若对其进行两路归并排序,则先将这8个记录看成长度为1的8个有序子文件,然后逐步两两归并,直至最后达到全部关键字有序为止。其具体的归并排序过程如图8-2所示。图8-2二路归并排序示例

3.快速排序

快速排序算法是基于分治策略的排序算法之一。其基本思想是对输入的数组R[l:h]按以下三个步骤进行排序:

步骤一:分解(Divide)。以R[l]为基准元素将R[l:h]划分为三段:R[l:q-1],R[q]和R[q+1:h],且使R[l:q-1]中任何元素不大于R[q],R[q+1:h]中任何一个元素大于R[q],下标q在划分过程中确定。

步骤二:递归求解(Conquer)。通过递归调用快速排序算法分别对R[l:q-1]和R[q+1:h]进行排序。

步骤三:合并(Merge)。由于对R[l:q-1]和R[q+1:h]的排序是就地进行的,因此实际上不需要进一步的合并计算。图8-3快速排序示例一般来说,快速排序有非常好的时间复杂度,它优于各种排序算法。可以证明,对n个记录进行快速排序的平均时间复杂度为O(nlbn)。但是,当待排序文件的记录已按关键字有序或基本有序时,情况反而恶化了,原因是在第一趟快速排序中,经过n-1次比较之后,将第一个记录仍定位在它原来的位置上,并得到一个包括n-1个记录的子文件;第二次递归调用,经过n-2次比较,将第二个记录仍定位在它原来的位置上,从而得到一个包括n-2个记录的子文件;依次类推,最后得到的总比较次数为

(8-3)

这使快速排序蜕变为起泡排序,其时间复杂度为O(n2)。在这种情况下,通常采用“三者取中”的规则加以改进。即在进行一趟快速排序之前,对R[l],R[h] 和R[

(l+h)/2

] 进行比较,再将三者中取中值的记录和R[l] 交换,就可以改善快速排序在最坏情况下的性能。在最好情况下,每次划分所取的基准都是无序区的中值记录,划分的结果是基准的左、右两个无序子区的长度大致相等。设C(n)表示对长度为n的文件进行快速排序所需的比较次数,显然它应该等于对长度为n的无序区进行划分所需的比较次数n-1,加上递归地对划分所得的左、右两个无序子区(长度≤n/2)进行快速排序所需的比较次数。假设文件长度n=2k,那么总的比较次数为

(8-4)

其中,C(1)是一个常数;k=lbn。

8.2动态规划

动态规划法与分治法类似,其基本思想也是将待求解问题分解成若干个子问题,先求解子问题,然后从这些子问题的解得到原问题的解。与分治法不同的是,适用于动态规划法求解的问题,经分解得到的子问题往往不是互相独立的。若用分治法解这类问题,则分解得到的子问题数量太大,以至于最后解决原问题需要耗费指数级的时间。另外,在用分治法求解时,有些子问题被重复计算了许多次。基于动态规划法的算法设计通常按以下四个步骤进行:

(1)找出最优解的性质,并描述其结构特征。

(2)递归定义最优值。

(3)以自底向上的方式计算最优值。

(4)根据计算最优值时得到的信息构造一个最优解。

1.矩阵连乘问题

给定n个矩阵{A0,A1,…,An-1},其中Ai和Ai+1是可

乘的,i=0,1,…,n-2。要求计算这n个矩阵的连乘积A0A1…An-1。

由于矩阵乘法满足结合律,因此计算矩阵连乘可以有许多不同的计算次序,每种计算次序都可用不同的加括号方式确定。如果矩阵连乘完全加了括号,则说明计算矩阵连乘的次序也完全确定,这时就可以使用两个矩阵相乘的标准算法计算矩阵的连乘积。完全加括号的矩阵连乘积可以递归定义为

(1)单个矩阵是完全加括号的。

(2)矩阵连乘积A是完全加括号的,则A可以表示为两个完全加括号的矩阵B和C的乘积并加括号,即A=(BC)。

2.矩阵连乘积的最优计算次序

(1)分析最优解的结构。

设将矩阵连乘积A0A1…An-1记为A[0:n-1],计算A[0:n-1]的一个最优计算次序。设一个计算次序在矩阵Ak和Ak+1之间断开,0≤k<n-1,则完全加括号方式为((A0…Ak)(Ak+1…An-1))。首先依此次序先分别计算A[0:k]和A[k+1:n-1],然后将计算的结果相乘得到A[0:n-1]。它的总计算量为A[0:k]的计算量加上A[k+1:n-1]的计算量,再加上A[0:k]和A[k+1:n-1]相乘的计算量的和。这个问题的关键特征是:计算A[0:n-1]的一个最优计算次序,其所包含的计算矩阵子链A[0:k]和A[k+1:n-1]的计算次序也是最优的。

因此,矩阵连乘积计算次序问题的最优解包含着其子问题的最优解,该性质称为最优子结构性质。一个问题是否具有最优子结构性质,是该问题是否可以用动态规划法求解的重要前提。

(2)建立递归关系。

对于矩阵连乘积的最优计算次序问题,设计算A[i:j]

(0≤i≤j≤n-1)所需的最少数乘次数为m[i][j],则原问题的最优值为m[0][n-1]。

①当i=j时,A[i:j]=Ai为单一矩阵,无须计算,因此m[i][i]=0,i=0,1,…,n-1。

②当i<j时,可利用最优子结构性质计算m[i][j]。若计算A[i:j]的最优次序是在Ak和Ak+1之间断开,i≤k<j,则m[i][j]=m[i][k]+m[k+1][j]+pipk+1pj+1。由于计算时是不知道断开点k的位置,因此k还未确定。不过k的位置只有j-i种可能,即k∈{i,i+1,…,j-1},k是j-i个位置中使计算量达到最小的那个位置。因此,m[i][j]可以递归定义为

(8-5)

若将m[i][j]的断开位置k记为s[i][j]=k,则在计算出最优值m[i][j]后,可由s[i][j]递归地构造出相应的最优解。

(3)计算最优值。

根据计算m[i][j] 的递归式(8-5),容易编写递归算法计算m[0][n-1],但简单地使用递归算法计算将耗费指数级的计算时间。事实上,在递归计算过程中,对于0≤i≤j≤n-1时,不同的有序对(i,j)对应于不同的子问题,不同的子问题个数只有个。由此可见,在递归计算时许多子问题被重复计算多次,这也是该问题可以用动态规划法求解的显著特征之一。例如,计算矩阵连乘积A0A1A2A3A4A5,其中各矩阵

的维数分别为30×35、35×15、15×5、5×10、10×20、20×25。

用动态规划算法MatrixChain计算m[i][j] 的先后次序如图8-4(a)所示,计算结果m[i][j]和s[i][j](0≤i≤j≤n-1)如图8-4(b)和(c)所示。图8-4计算m[i][j]的次序在计算m[1][4] 时,根据递归式(8-5)有

(8-6)

且k=3,因此s[2][5]=3。

(4)构造最优解。

MatrixChain算法的结果只给出了计算矩阵连乘积的最

少数乘次数,还不知道采用何种计算次序才能达到最少数

乘次数。8.2.1动态规划算法的基本要素

1.最优子结构

设计动态规划算法的第一步是分析最优解的结构,当问题的最优解包含了其子问题的最优解时,称该问题具有最优子结构性质。

在矩阵连乘积最优计算次序问题中,若A0A1…An-1的最优完全加括号方式在Ak和Ak+1之间将矩阵链断开,则由此确定的子矩阵链A0A1…Ak和Ak+1Ak+2…An-1的完全加括号方式也最优。

2.重叠子问题

可以用动态规划算法求解的问题,应具有的另一个基本要素是子问题的重叠性质。在用递归算法自顶向下解此问题时,每次产生的问题并不总是新问题,有些子问题被反复计算多次。动态规划算法正是利用了这种问题的重叠性质,对每个子问题只解一次,然后将其解保存在一个表格中,当再次需要解此子问题时,只是简单地用常数时间查看所保存的结果即可。图8-5计算A[1:4]的递归树

3.备忘录方法

动态规划算法的一个变形是备忘录方法。备忘录方法使用一个表格记录已解决子问题的结果,在下次需要解此子问题时,只须察看该子问题的结果,而不必重新计算。与动态规划不同的是备忘录方法的递归方式是自顶向下,而动态规划算法则是自底向上的。因此,备忘录方法的控制结构与直接递归方法的控制结构相同,区别在于备忘录方法为每个解过的子问题建立备忘录,避免了相同子问题的重复求解。8.2.2动态规划应用之图像压缩

在计算机中常用像素点的灰度值序列{p0,p1,…,pn-1}表示图像,其中整数pi(0≤i≤n-1)表示像素点i的灰度值。通常灰度值的范围是0~255,因此需要用8个比特表示一个像素。

图像的变位压缩存储格式是将所给的像素点序列{p0,p1,…,pn-1}分割成m个连续段S0,S1,…,Sm-1,第i个像素段Si(0≤i≤m-1)中有l[i]个像素,且该段中每个像素都由b[i]位表示。设t[i]=

(0≤i≤m-1),则第i个像素段Si={pt[i],

…,pt[i]+l[i]-1}(0≤i≤m-1)。

设hi= ,则hi≤b[i]≤8,因此需要3个比特表示b[i](0≤i≤m-1)。如果限制1≤l[i]

≤255,则需要8个比特表示l[i](0≤i≤m-1)。这样,第i个像素段所需的存储空间为l[i]*b[i]+11比特,像素序列{p0,p1,

…,pn-1}所需的存储空间为。图像压缩问题要求确定像素序列{p0,p1,…,pn-1}的一个最优分段,使得依此分段所需的存储空间最少。其中,0≤pi≤255,0≤i≤n-1,每个分段的长度不超过256位。

(1)最优子结构。

设l[i]和b[i](0≤i≤m-1)是{p0,p1,…,pn-1}的一个最优分段,显而易见,l[1] 和b[1]是{p0,p1,…,pl[1]-1}的一个最优分段,且l[i] 和b[i](1≤i≤m-1)是{pl[i],pl[i]+1,…,pn-1}的一个最优分段,即图像压缩问题满足最优子结构性质。

(2)递归计算最优值。

设s[i](0≤i≤m-1)是{p0,p1,…,pn-1}的最优分段所需的存储位数,由最优子结构性质可知:

(8-7)

其中,bmax(i,j)=。

(3)构造最优解。

Compress算法中用l[i]和b[i]记录了最优分段所需的信息,最优分段最后一个段的段长度和像素位数存储于l[i]

和b[i]中,其前一段的段长度和像素位数存储于l[n-l[n]]和

b[n-b[n]]中,依次类推,由计算得出的l[i]和b[i]可在时间

复杂度为O(n)以内构造出相应的最优解。

(4)计算复杂度。

Compress算法需要的空间复杂度为O(n)。

由于Compress算法中对j的循环次数不超过256,因此

对每一个确定的i,可在时间复杂度为以O(1)内完成

的计算,最终整个算法所需的计算时间复杂度为O(n)。8.2.3动态规划应用之最优二叉搜索树

设S={x1,x2,…,xn}是一个有序集,且x1<x2<…<xn。有序集S的二叉搜索树,利用二叉树的结点存储有序集中的元素,它具有下述性质:存储于每个结点中的元素,大于其左子树中任意结点所存储的元素,小于其右子树中任意结点所存储的元素。二叉搜索树的叶子结点是形如(xi,xi+1)的开区间。在表示S的二叉搜索树中搜索一个元素x,其返回的结果有两种情况:

(1)在二叉搜索树的内结点中找到x=xi。

(2)在二叉搜索树的内结点中确定。设在第一种情况中找到元素x的概率是bi,在第二种情况中确定的概率是ai,其中约定,

。显然有

(8-8)

其中,(a0,b1,a1,…,bn,an)称为集合S的存取概率分布。在表示S的二叉搜索树T中,设存储元素xi的结点深度为ci,叶子结点的深度为dj,则

(8-9)

其中,p表示在二叉搜索树T中做一次搜索所需的平均比较次数,也称为二叉搜索树T的平均路长。一般情况下,不同二叉搜索树的平均路长是不同的。

最优二叉搜索树问题是有序集S及其存取概率分布(a0,b1,a1,…,bn,an)在所有表示有序集S的二叉搜索树中,找出一棵具有最小平均路长的二叉搜索树。

(1)最优子结构性质。

含有结点xi,…,xj和叶子结点(xi-1,xi),…,(xj,xj+1)的二叉搜索树T,可以看做是有序集{xi,…,xj}关于全集{xi-1,…,xj+1}的一棵二叉搜索树,其存取概率是下面的条件概率:

(8-10)设Ti,j是有序集{xi,…,xj}关于存取概率

的一棵最优二叉搜索树,其平均路长为pi,j;Ti,j的根结点存储元素为xm,其左子树Tl和右子树Tr的平均路长分别为pl和pr。由于Tl和Tr中结点深度是它们在Ti,j中结点深度减去1,因此

(8-11)由于Tl是关于集合{xi,…,xm-1}的一棵二叉搜索树,因此pl≥pi,m-1。若pl>pi,m-1,则用Ti,m-1替换Tl可得到平均路长比Ti,j更小的二叉搜索树,这与Ti,j是最优二叉搜索树相矛盾,故Tl是一棵最优二叉搜索树。同理可得,Tr也是一棵最优二叉搜索树。因此,最优二叉搜索树问题具有最优子结构性质。

(2)递归计算最优值。

设最优二叉搜索树Ti,j的平均路长为pi,j,所求的最优值为p1,n。由最优二叉搜索树的最优子结构性质可建立计算

pi,j的递归式如下:初始时pi,i-1=0,1≤i≤n。记wi,jpi,j为m(i,j),则m(1,n)=w1,np1,n=p1,n为所求的最优值。

计算m(i,j)的递归式为

(8-12)

(3)构造最优解。

在OptimalBinarySearchTree算法中,用s[i][j]保存了最优子树Ti,j根结点中的元素,当s[1][n]=k时,xk为所求二叉搜索树的根结点元素;其左子树为T1,k-1,因此i=s[1][k-1] 表示T(1,k-1)的根结点元素为xi;依次类推,由s中的信息可以在时间复杂度为O(n)以内构造出所求的最优二叉搜索树。

(4)计算复杂度。

在OptimalBinarySearchTree算法中用到三个数组分别为m、s和w,故该算法所需的空间复杂度为O(n2),它的主要计算量在于计算{m(i,k-1)+m(k+1,j)}的值。对于固定的r,它所需要的计算时间复杂度为O(j-i+1)=O(r+1),因此该算法所耗费的总时间复杂度为。可以证明:

8.3贪心算法

当一个问题具有最优子结构性质时,可以用动态规划算法求解,但有时会有更简单有效的算法。例如,假设有四种硬币,它们的面值分别是五角、一角、五分和一分,现在找给某顾客四角七分钱,该如何找零,谁都会!硬币找零的计算方法实质上称为贪心算法,其基本思想是:总是做出在当前看来是最好的选择,即贪心算法并不从整体最优上考虑,而只考虑当前(局部)最优。硬币找零的计算结果是整体(全局)最优解,但贪心算法的解并不都是最优的,可以认为是最优解的近似解。

活动安排问题是可以用贪心算法求解的一个很好的例子,该问题要求高效地安排一系列占用某一个公共资源的活动。8.3.1贪心算法与动态规划算法的差异

在动态规划算法中,每步所做出的选择往往依赖于相关子问题的解,因此只有在求出相关子问题的解以后才能做出选择。而贪心算法所做的贪心选择是仅在当前状态下做出的最好选择,即局部最优选择;然后再求解做出该选择后所产生的相应子问题的解,即贪心算法所做出的贪心选择可以依赖于“过去”所做出的选择,但绝不依赖于将来所做出的选择,也不依赖于子问题的解。贪心算法和动态规划算法都具有最优子结构性质。下面通过事例说明这两者之间的差别。

(1) 0-1背包问题。

(2)背包问题。图8-60-1背包问题和背包问题差异之实例说明8.3.2贪心算法应用之哈夫曼编码

哈夫曼编码是用于数据文件压缩的一个十分有效的编码方法,它利用一个字符在文件中出现的频率建立一个用0-1串表示各个字符的最优表示方法。

假设有一个数据文件包含100000个字符,其中共有六个字符形式,每个字符出现的频率如表8-1所示。问题是:如何采用压缩存储方式存储该文件。译码过程必须方便地获取编码的前缀,因此需要一个表示前缀码的合适的数据结构,为此采用二叉树作为表示前缀编码的数据结构。在二叉树中,叶子代表给定的字符,并将每个字符的前缀码看做是从根到代表该字符的叶子的一条路经,代码中的每一位0或1分别作为指示某结点到左孩子或右孩子的“路标”。例如,图8-7中的两棵树分别表示表8-1中的编码方案所对应的数据结构。图8-7前缀码的二叉树表示给定编码字符集C及其频率分布f,C的一个前缀码编码方案对应一个二叉树T,字符c∈C在树T中的深度记为dT(c),其中dT(c)也是字符c的前缀码长。该编码方案的平均码长定义为

(8-13)

使平均码长达到最小的前缀编码称为C的一个最优前缀码。下面考虑哈夫曼编码的正确性。只要能够证明最优前缀码问题具有贪心选择性质和最优子结构性质,就可以证明哈夫曼编码是正确的。

(1)证明最优子结构性质。

设T表示字符集C的一个最优前缀码的二叉树,C中字符c的出现频率为f(c),x和y是树T中的两个兄弟叶子,z是x和y的双亲,若将z看做频率为f(z)=f(x)+f(y)的字符,则树T'=T-{x,y}表示字符集C'=C-{x,y}∪{z}的一个最优前缀码。证明:T的平均码长用T‘的码长表示。

对于任意c∈C-{x,y},有dT(c)=dT’(c),故f(c)dT(c)=

f(c)dT‘(c)。另外,dT(x)=dT(y)=dT’(z)+1,故:

f(x)dT(x)+f(y)dT(y)=(f(x)+f(y))(dT‘(z)+1)

=f(x)+f(y)+f(z)dT’(z)

(8-14)

因此,B(T)=B(T')+f(x)+f(y)。若T'所表示的字符集C'的前缀码不是最优的,则有T“ 表示的C' 的前缀码使得B(T'')<B(T')。由于将z看做C'中的一个字符,因此z在T“中是树叶。若将x和y加入树T''中作为z的孩子,则得到字符集C的前缀码的二叉树T''',且有

(8-15)

这与T是最优前缀码相矛盾,故T'所表示的前缀码也是最优的。

(2)证明贪心选择性质。

设C是编码字符集,C中字符c的频率为f(c),x和y是C中具有最小频率的两个字符,则存在C的一个最优前缀码使x和y具有相同的码长且它们的最后一位编码不同。

设二叉树T表示C的任意一个最优前缀码,我们要证明在对T做适当修改后可以得到一棵新的二叉树T',使得在新树中x和y是最深叶子且互为兄弟,同时新树T'表示的前缀码也是C的一个最优前缀码。如果能做到这一点,则x和y在T'表示的前缀码中具有相同的码长且仅最后一位编码不同。证明:设b和c是二叉树T的最深叶子且为兄弟,不失一般性,设f(b)≤f(c),f(x)≤f(y)。由于x和y是C中具有最小频率的两个字符,因此f(x)≤f(b),f(y)≤f(c)。

将树T中的叶子x和b交换得到树T‘,再将y和c交换得到树T",则

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论