检查数字是否为完全平方数

2024-12-30 08:41:00
admin
原创
68
摘要:问题描述:我如何检查一个数字是否是完全平方数?就目前而言,速度不是问题,只是工作而已。另请参阅:python 中的整数平方根。解决方案 1:依赖任何浮点计算(math.sqrt(x), 或x**0.5)的问题在于,您无法真正确定其是否准确(对于足够大的整数x,它不会准确,甚至可能会溢出)。幸运的是(如果不着急...

问题描述:

我如何检查一个数字是否是完全平方数?

就目前而言,速度不是问题,只是工作而已。


另请参阅:python 中的整数平方根。


解决方案 1:

依赖任何浮点计算(math.sqrt(x), 或x**0.5)的问题在于,您无法真正确定其是否准确(对于足够大的整数x,它不会准确,甚至可能会溢出)。幸运的是(如果不着急的话;-)有许多纯整数方法,例如以下方法……:

def is_square(apositiveint):
  x = apositiveint // 2
  seen = set([x])
  while x * x != apositiveint:
    x = (x + (apositiveint // x)) // 2
    if x in seen: return False
    seen.add(x)
  return True

for i in range(110, 130):
   print i, is_square(i)

提示:它基于平方根的“巴比伦算法”,请参阅维基百科。它适用于任何正数,只要您有足够的内存来完成计算;-)。

编辑:让我们看一个例子......

x = 12345678987654321234567 ** 2

for i in range(x, x+2):
   print i, is_square(i)

这将根据需要打印(并且在合理的时间内;-):

152415789666209426002111556165263283035677489 True
152415789666209426002111556165263283035677490 False

请在提出基于浮点中间结果的解决方案之前,确保它们在这个简单的例子上正常工作 - 这并不(您只需要进行一些额外的检查,以防计算出的 sqrt 有一点偏差),只是需要稍微小心一点。

然后尝试x**7找到巧妙的方法来解决你所遇到的问题,

OverflowError: long int too large to convert to float

当然,随着数字不断增长,你必须变得越来越聪明。

如果我着急,当然,我会使用gmpy ——但是,我显然有偏见 ;-)。

>>> import gmpy
>>> gmpy.is_square(x**7)
1
>>> gmpy.is_square(x**7 + 1)
0

是的,我知道,这太简单了,感觉就像作弊(有点像我对 Python 的总体感觉 ;-) - 根本没有聪明,只是完美的直接和简单(并且,对于 gmpy 来说,速度非常快 ;-)...

解决方案 2:

使用牛顿法快速找到最接近的整数平方根,然后求其平方,看看它是否是你想要的数字。请参阅isqrt。

Python ≥ 3.8 有math.isqrt。如果使用旧版本的 Python,请在此处def isqrt(n)查找“ ”实现。

import math

def is_square(i: int) -> bool:
    return i == math.isqrt(i) ** 2

解决方案 3:

如果您有兴趣,我有一个纯数学的回答来回答数学 stackexchange 上的一个类似问题,“比提取平方根更快地检测完全平方数”。

我自己实现的 isSquare(n) 可能不是最好的,但我喜欢它。我花了几个月的时间学习数学理论、数字计算和 Python 编程,将自己与其他贡献者进行比较等,才真正理解了这种方法。不过我喜欢它的简单性和效率。我还没有见过比它更好的。告诉我你的想法。

def isSquare(n):
    ## Trivial checks
    if type(n) != int:  ## integer
        return False
    if n < 0:      ## positivity
        return False
    if n == 0:      ## 0 pass
        return True

    ## Reduction by powers of 4 with bit-logic
    while n&3 == 0:    
        n=n>>2

    ## Simple bit-logic test. All perfect squares, in binary,
    ## end in 001, when powers of 4 are factored out.
    if n&7 != 1:
        return False

    if n==1:
        return True  ## is power of 4, or even power of 2


    ## Simple modulo equivalency test
    c = n%10
    if c in {3, 7}:
        return False  ## Not 1,4,5,6,9 in mod 10
    if n % 7 in {3, 5, 6}:
        return False  ## Not 1,2,4 mod 7
    if n % 9 in {2,3,5,6,8}:
        return False  
    if n % 13 in {2,5,6,7,8,11}:
        return False  

    ## Other patterns
    if c == 5:  ## if it ends in a 5
        if (n//10)%10 != 2:
            return False    ## then it must end in 25
        if (n//100)%10 not in {0,2,6}: 
            return False    ## and in 025, 225, or 625
        if (n//100)%10 == 6:
            if (n//1000)%10 not in {0,5}:
                return False    ## that is, 0625 or 5625
    else:
        if (n//10)%4 != 0:
            return False    ## (4k)*10 + (1,9)


    ## Babylonian Algorithm. Finding the integer square root.
    ## Root extraction.
    s = (len(str(n))-1) // 2
    x = (10**s) * 4

    A = {x, n}
    while x * x != n:
        x = (x + (n // x)) >> 1
        if x in A:
            return False
        A.add(x)
    return True

非常简单。首先,它检查我们是否有一个整数,并且是正数。否则就没有意义了。它让 0 作为 True 溜走(这是必要的,否则下一个块就是无限循环)。

下一个代码块使用位移位和位逻辑运算,在一个非常快速的子算法中系统地删除 4 的幂。我们最终不是找到原始 n 的 isSquare,而是找到按 4 的幂缩小的 k<n(如果可能的话)。这减少了我们正在处理的数字的大小,并真正加快了巴比伦方法的速度,但也使其他检查也更快。

第三段代码执行一个简单的布尔位逻辑测试。任何完全正方形的二进制最低有效三位数字都是 001。始终如此。除了由 4 的幂产生的前导零,这已经说明过了。如果它未通过测试,您立即知道它不是正方形。如果它通过了测试,您就不能确定了。

另外,如果我们最终得到的测试值为 1,则测试数字最初是 4 的幂,可能包括 1 本身。

与第三块一样,第四块使用简单的模数运算符测试十进制的个位值,并倾向于捕获通过前一个测试的值。还有模 7、模 8、模 9 和模 13 测试。

第五段代码检查一些众所周知的完美正方形模式。以 1 或 9 结尾的数字前面是 4 的倍数。以 5 结尾的数字必须以 5625、0625、225 或 025 结尾。我曾添加过其他数字,但后来意识到它们是多余的或从未实际使用过。

最后,第六段代码与最佳答题者 Alex Martelli 的答案非常相似。基本上使用古巴比伦算法求平方根,但将其限制为整数值,同时忽略浮点数。这样做既是为了提高速度,也是为了扩展可测试值的大小。我使用集合而不是列表,因为它花费的时间少得多,我使用位移位而不是除以二,而且我聪明地选择了一个初始值,效率更高。

顺便说一句,我确实测试了 Alex Martelli 推荐的测试数字,以及一些数量级大很多的数字,例如:

x=1000199838770766116385386300483414671297203029840113913153824086810909168246772838680374612768821282446322068401699727842499994541063844393713189701844134801239504543830737724442006577672181059194558045164589783791764790043104263404683317158624270845302200548606715007310112016456397357027095564872551184907513312382763025454118825703090010401842892088063527451562032322039937924274426211671442740679624285180817682659081248396873230975882215128049713559849427311798959652681930663843994067353808298002406164092996533923220683447265882968239141724624870704231013642255563984374257471112743917655991279898690480703935007493906644744151022265929975993911186879561257100479593516979735117799410600147341193819147290056586421994333004992422258618475766549646258761885662783430625 ** 2
for i in range(x, x+2):
    print(i, isSquare(i))

打印结果如下:

1000399717477066534083185452789672211951514938424998708930175541558932213310056978758103599452364409903384901149641614494249195605016959576235097480592396214296565598519295693079257885246632306201885850365687426564365813280963724310434494316592041592681626416195491751015907716210235352495422858432792668507052756279908951163972960239286719854867504108121432187033786444937064356645218196398775923710931242852937602515835035177768967470757847368349565128635934683294155947532322786360581473152034468071184081729335560769488880138928479829695277968766082973795720937033019047838250608170693879209655321034310764422462828792636246742456408134706264621790736361118589122797268261542115823201538743148116654378511916000714911467547209475246784887830649309238110794938892491396597873160778553131774466638923135932135417900066903068192088883207721545109720968467560224268563643820599665232314256575428214983451466488658896488012211237139254674708538347237589290497713613898546363590044902791724541048198769085430459186735166233549186115282574626012296888817453914112423361525305960060329430234696000121420787598967383958525670258016851764034555105019265380321048686563527396844220047826436035333266263375049097675787975100014823583097518824871586828195368306649956481108708929669583308777347960115138098217676704862934389659753628861667169905594181756523762369645897154232744410732552956489694024357481100742138381514396851789639339362228442689184910464071202445106084939268067445115601375050153663645294106475257440167535462278022649865332161044187890625 True
1000399717477066534083185452789672211951514938424998708930175541558932213310056978758103599452364409903384901149641614494249195605016959576235097480592396214296565598519295693079257885246632306201885850365687426564365813280963724310434494316592041592681626416195491751015907716210235352495422858432792668507052756279908951163972960239286719854867504108121432187033786444937064356645218196398775923710931242852937602515835035177768967470757847368349565128635934683294155947532322786360581473152034468071184081729335560769488880138928479829695277968766082973795720937033019047838250608170693879209655321034310764422462828792636246742456408134706264621790736361118589122797268261542115823201538743148116654378511916000714911467547209475246784887830649309238110794938892491396597873160778553131774466638923135932135417900066903068192088883207721545109720968467560224268563643820599665232314256575428214983451466488658896488012211237139254674708538347237589290497713613898546363590044902791724541048198769085430459186735166233549186115282574626012296888817453914112423361525305960060329430234696000121420787598967383958525670258016851764034555105019265380321048686563527396844220047826436035333266263375049097675787975100014823583097518824871586828195368306649956481108708929669583308777347960115138098217676704862934389659753628861667169905594181756523762369645897154232744410732552956489694024357481100742138381514396851789639339362228442689184910464071202445106084939268067445115601375050153663645294106475257440167535462278022649865332161044187890626 False

它只用了 0.33 秒就完成了此操作。

在我看来,我的算法与 Alex Martelli 的算法一样,具有所有优点,但还有一个额外的好处,那就是高效的简单测试拒绝,可以节省大量时间,更不用说测试数字的大小减少了 4 的幂,这提高了速度、效率、准确性和可测试数字的大小。在非 Python 实现中可能尤其如此。

在实施巴比伦根提取之前,大约 99% 的整数被拒绝为非平方数,而巴比伦根提取所需的时间仅为拒绝整数的 2/3。尽管这些测试并没有显著加快这一过程,但通过除以所有 4 的幂将所有测试数字减少为奇数确实加速了巴比伦测试。

我做了一个时间对比测试。我连续测试了从 1 到 1000 万的所有整数。仅使用巴比伦方法(使用我特别定制的初始猜测),我的 Surface 3 平均需要 165 秒(准确率为 100%)。仅使用我的算法中的逻辑测试(不包括巴比伦),它花费了 127 秒,它将 99% 的整数拒绝为非平方数,而不会错误地拒绝任何完全平方数。在通过的整数中,只有 3% 是完全平方数(密度要高得多)。使用上述采用逻辑测试和巴比伦根提取的完整算法,我们的准确率为 100%,并且仅用 14 秒即可完成测试。前 1 亿个整数大约需要 2 分 45 秒进行测试。

编辑:我已经能够进一步缩短时间。我现在可以在 1 分 40 秒内测试 0 到 1 亿的整数。检查数据类型和正数浪费了很多时间。消除前两个检查,我将实验时间缩短了一分钟。必须假设用户足够聪明,知道负数和浮点数不是完全平方数。

解决方案 4:

由于在处理浮点计算(例如计算平方根的方法)时永远不能依赖精确的比较,因此不太容易出错的实现是

import math

def is_square(integer):
    root = math.sqrt(integer)
    return integer == int(root + 0.5) ** 2

想象integer一下9math.sqrt(9)可能是3.0,但也可能是2.999993.00001,所以直接求平方结果并不可靠。知道int取底值,首先将浮点值增加,意味着如果我们处于一个范围内,并且仍然具有足够精细的分辨率来表示接近我们正在寻找的数字,0.5我们将获得我们正在寻找的值。float

解决方案 5:

import math

def is_square(n):
    sqrt = math.sqrt(n)
    return (sqrt - int(sqrt)) == 0

完全平方数是可以表示为两个相等整数的乘积的数。math.sqrt(number)返回 a floatint(math.sqrt(number))将结果转换为int

如果平方根是整数,例如 3,则为math.sqrt(number) - int(math.sqrt(number))0,语句ifFalse。如果平方根是实数,例如 3.2,则为True并打印“它不是完全平方数”。

对于较大的非正方形(例如 152415789666209426002111556165263283035677490)则无法正常工作。

解决方案 6:

我的答案是:

def is_square(x):
    return x**.5 % 1 == 0

它基本上是求平方根,然后对 1 取模以去除整数部分,如果结果为 0 则返回,True否则返回False。在这种情况下,x 可以是任何大数,只是不能大于 python 可以处理的最大浮点数:1.7976931348623157e+308

对于较大的非正方形(例如 152415789666209426002111556165263283035677490)来说,这是不正确的。

解决方案 7:

可以使用模块来解决这个问题,以获得任意精度decimal的平方根,并轻松检查“准确性”:

import math
from decimal import localcontext, Context, Inexact

def is_perfect_square(x):
    # If you want to allow negative squares, then set x = abs(x) instead
    if x < 0:
        return False

    # Create localized, default context so flags and traps unset
    with localcontext(Context()) as ctx:
        # Set a precision sufficient to represent x exactly; `x or 1` avoids
        # math domain error for log10 when x is 0
        ctx.prec = math.ceil(math.log10(x or 1)) + 1  # Wrap ceil call in int() on Py2
        # Compute integer square root; don't even store result, just setting flags
        ctx.sqrt(x).to_integral_exact()
        # If previous line couldn't represent square root as exact int, sets Inexact flag
        return not ctx.flags[Inexact]

为了演示真正巨大的价值:

# I just kept mashing the numpad for awhile :-)
>>> base = 100009991439393999999393939398348438492389402490289028439083249803434098349083490340934903498034098390834980349083490384903843908309390282930823940230932490340983098349032098324908324098339779438974879480379380439748093874970843479280329708324970832497804329783429874329873429870234987234978034297804329782349783249873249870234987034298703249780349783497832497823497823497803429780324
>>> sqr = base ** 2
>>> sqr ** 0.5  # Too large to use floating point math
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
OverflowError: int too large to convert to float

>>> is_perfect_power(sqr)
True
>>> is_perfect_power(sqr-1)
False
>>> is_perfect_power(sqr+1)
False

如果增加被测试值的大小,最终会变得相当慢(对于 200,000 位的正方形,需要近一秒钟),但对于更适中的数字(例如 20,000 位),它仍然比人类注意到的单个值要快(在我的机器上约为 33 毫秒)。但由于速度不是您的主要考虑因素,因此使用 Python 的标准库是一种很好的方法。

gmpy2当然,使用并测试会快得多gmpy2.mpz(x).is_square(),但如果您不喜欢第三方包,上述方法也很好用。

解决方案 8:

我刚刚在另一个主题(寻找完美正方形)上发布了对上面的一些示例的细微改动,并且认为我会在这里包含我发布的内容的细微改动(使用 nsqrt 作为临时变量),以防它引起兴趣/使用:

import math

def is_square(n):
  if not (isinstance(n, int) and (n >= 0)):
    return False 
  else:
    nsqrt = math.sqrt(n)
    return nsqrt == math.trunc(nsqrt)

对于较大的非正方形(例如 152415789666209426002111556165263283035677490)来说,这是不正确的。

解决方案 9:

@Alex Martelli 解决方案的一个变体,无需set

时间x in seenTrue

  • 在大多数情况下,它是最后添加的一个,例如 1022 产生序列x511、256、129、68、41、32、31、31 ;

  • 在某些情况下(即对于完全平方数的前身),它是倒数第二个添加,例如 1023 产生 511、256、129、68、41、32、31、32 。

因此,只要当前值x大于或等于前一个值,就可以停止:

def is_square(n):
    assert n > 1
    previous = n
    x = n // 2
    while x * x != n:
        x = (x + (n // x)) // 2
        if x >= previous:
            return False
        previous = x
    return True

x = 12345678987654321234567 ** 2
assert not is_square(x-1)
assert is_square(x)
assert not is_square(x+1)

与针对 1 < n < 10**7 测试的原始算法等效。在相同的间隔内,这个稍微简单的变体速度大约快 1.4 倍。

解决方案 10:

这是我的方法:

def is_square(n) -> bool:
    return int(n**0.5)**2 == int(n)

取数字的平方根。转换为整数。取平方。如果数字相等,则为完全平方,否则不为完全平方。

对于像 152415789666209426002111556165263283035677489 这样的大正方形来说,这是不正确的。

解决方案 11:

如果除以平方根剩下的模数(余数)为 0,那么它就是完全平方数。

def is_square(num: int) -> bool:
    return num % math.sqrt(num) == 0

我根据 1000 以内的完全平方数列表检查了这一点。

解决方案 12:

通过观察发现,如果从 n 的平方根以上开始,连续项将形成一个递减序列,从而可以改进巴比伦方法。

def is_square(n):
    assert n > 1
    a = n
    b = (a + n // a) // 2
    while b < a:
        a = b
        b = (a + n // a) // 2
    return a * a == n

解决方案 13:

如果它是一个完全平方数,它的平方根将是一个整数,小数部分将为 0,我们可以使用模数运算符来检查小数部分,并检查它是否为 0,对于某些数字来说它确实会失败,所以,为了安全起见,即使小数部分为 0,我们也会检查它是否是平方根的平方。

import math

def isSquare(n):
    root = math.sqrt(n)
    if root % 1 == 0:
        if int(root) * int(root) == n:
            return True
    return False

isSquare(4761)

解决方案 14:

你可以用二分查找法找到四舍五入后的平方根。计算结果的平方,看看它是否与原始值相符。

您可能更愿意接受 FogleBirds 的答案 - 但要小心,因为浮点运算是近似的,这可能会使这种方法失效。原则上,您可能会从一个比完全平方大一的大整数中得到假阳性,例如,由于精度损失。

解决方案 15:

一个简单的方法(比第二个更快):

def is_square(n):  
     return str(n**(1/2)).split(".")[1] == '0'

另一种方法:

def is_square(n):   
    if n == 0:
        return True
    else:
        if n % 2 == 0 :
            for i in range(2,n,2):
                if i*i == n:
                    return True
        else :
            for i in range(1,n,2):
                if i*i == n:
                    return True
    return False

解决方案 16:

这是一个优雅、简单、快速且任意的解决方案,适用于 Python 版本 >= 3.8:

版本 1:

from math import isqrt

def is_square(number):
    if number >= 0:
        return isqrt(number) ** 2 == number
    return False

版本 2:

def is_square2(number):
    return isqrt(number) ** 2 == number if number >= 0 else False

此版本遵循相同的类比,但比以前的版本快至少 68%。

解决方案 17:

这个答复与您提出的问题无关,但与我在您发布的代码中看到的一个隐含的问题有关,即“如何检查某个东西是否为整数?”

对这个问题你通常会得到的第一个答案是“不要!”而且确实在 Python 中,类型检查通常不是正确的做法。

但是,对于那些罕见的例外,不需要在数字的字符串表示中寻找小数点,而是使用isinstance函数:

>>> isinstance(5,int)
True
>>> isinstance(5.0,int)
False

当然,这适用于变量,而不是值。如果我想确定该是否为整数,我会这样做:

>>> x=5.0
>>> round(x) == x
True

但是正如其他人详细介绍的那样,在大多数此类非玩具示例中,都需要考虑浮点问题。

解决方案 18:

如果您想要循环遍历某个范围并针对每个非完全平方数执行某些操作,则可以执行以下操作:

def non_squares(upper):
    next_square = 0
    diff = 1
    for i in range(0, upper):
        if i == next_square:
            next_square += diff
            diff += 2
            continue
        yield i

如果你想对每个完全平方数做一些事情,生成器就更简单了:

(n * n for n in range(upper))

解决方案 19:

我认为这是可行的并且非常简单:

import math

def is_square(num):
    sqrt = math.sqrt(num)
    return sqrt == int(sqrt)

对于较大的非正方形(例如 152415789666209426002111556165263283035677490)来说,这是不正确的。

解决方案 20:

a=int(input('enter any number'))
flag=0
for i in range(1,a):
    if a==i*i:
        print(a,'is perfect square number')
        flag=1
        break
if flag==1:
    pass
else:
    print(a,'is not perfect square number')

解决方案 21:

在 kotlin 中:

它非常简单并且也通过了所有测试用例。

非常感谢>> https://www.quora.com/What-is-the-quickest-way-to-determine-if-a-number-is-a-perfect-square

fun isPerfectSquare(num: Int): Boolean {
    var result = false
    
    var sum=0L
    var oddNumber=1L
    
     while(sum<num){
         sum = sum + oddNumber
         oddNumber = oddNumber+2
     }
     
    result = sum == num.toLong()
    
 return result   
}

解决方案 22:

def isPerfectSquare(self, num: int) -> bool:
    left, right = 0, num
    while left <= right:
        mid = (left + right) // 2
        if mid**2 < num:
            left = mid + 1
        elif mid**2 > num:
            right = mid - 1
        else:
            return True
    return False

解决方案 23:

也许最简单的方法就是说

def perfectSquare(x):
   return (x == math.isqrt(x) ** 2)

该算法已经相当快了,因为它使用牛顿法来求整数平方根。但是,可以识别出很多永远不会是平方数的数字。例如,当你取 时x % 16,只0, 1, 4, 9需要根据该方法检查的余数isqrt(x)。如果没有 isqrt 方法,也可以使用巴比伦方法的思想,并将其与模数思想结合起来,得出

def perfectSquare(n):
    m = n % 16
    if m != 0 and m != 1 and m != 4 and m != 9:
      return False
    x = n
    while x * x > n:
        x = (x + n // x) // 2
    return x * x == n

解决方案 24:

  1. 确定数字的长度。

  2. 取增量 0.000000000000.......000001

  3. 查看 (sqrt(x))^2 - x 是否大于/等于/小于 delta,并根据 delta 误差做出决定。

解决方案 25:

import math

def is_square(n):
    sqrt = math.sqrt(n)
    return sqrt == int(sqrt)

对于较大的非正方形(例如 152415789666209426002111556165263283035677490)则无法正常工作。

解决方案 26:

这个想法是从 i = 1 运行一个循环到 floor(sqrt(n)),然后检查其平方是否等于 n。

bool isPerfectSquare(int n) 
{ 
    for (int i = 1; i * i <= n; i++) { 

        // If (i * i = n) 
        if ((n % i == 0) && (n / i == i)) { 
            return true; 
        } 
    } 
    return false; 
} 
相关推荐
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1008  
  在项目管理中,变更是一个不可避免的现象。无论是客户需求的调整、市场环境的变化,还是技术方案的更新,都可能引发项目的变更。如果处理不当,这些变更可能会导致项目延期、成本超支,甚至项目失败。因此,如何有效地应对项目变更,成为项目管理中的核心挑战之一。IPD(集成产品开发)作为一种高效的项目管理方法,其流程图不仅能够帮助团队...
IPD流程中的charter   0  
  IPD(Integrated Product Development,集成产品开发)是华为在长期实践中总结出的一套高效产品开发管理体系。它不仅帮助华为在全球市场中脱颖而出,也成为许多企业提升产品开发效率的参考标杆。IPD的核心在于通过跨部门协作、流程优化和资源整合,实现从需求分析到产品交付的全生命周期管理。通过实施IP...
IPD开发流程管理   0  
  华为IPD(集成产品开发)流程是一种以客户需求为导向、跨部门协同的高效项目管理方法。它通过系统化的流程设计和严格的阶段控制,确保项目从概念到交付的每个环节都能高效运作。IPD流程的核心在于打破传统职能部门的壁垒,将产品开发、市场、销售、供应链等关键环节整合到一个统一的框架中,从而实现资源的优化配置和信息的无缝流动。这种...
IPD流程中TR   0  
  在项目管理的实践中,CDCP(Certified Data Center Professional)认证评审是一个至关重要的环节。通过这一评审,项目团队不仅能够验证其数据中心设计和运营的合规性,还能提升整体管理水平。为了确保评审的顺利进行,准备一系列关键文档是必不可少的。这些文档不仅是评审的依据,也是项目团队与评审专家...
华为IPD是什么   0  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用