C# 优化(降低复杂性)。从n边长度计算锐角三角形、直角三角形和钝角三角形

C# 优化(降低复杂性)。从n边长度计算锐角三角形、直角三角形和钝角三角形,c#,.net,algorithm,time-complexity,C#,.net,Algorithm,Time Complexity,编辑1:将约束中的104更改为10^4。抱歉弄错了。 问题陈述: 我们有N根棍子。第i根棍子的大小是Ai。我们想知道从一根不同的棍子上每边创建的不同类型三角形的数量。计算锐角三角形、直角三角形和钝角三角形的数量 输入格式: 第一行包含N。 第二行包含N个整数。第i个数字表示Ai 约束条件: For full score: 3≤N≤5000 For 40% score: 3≤N≤500 6 2 3 9 10 12 15 2 1 4 对于所有测试用例: 1≤A[i]≤10^4 A[i]

编辑1:将约束中的104更改为10^4。抱歉弄错了。

问题陈述: 我们有N根棍子。第i根棍子的大小是Ai。我们想知道从一根不同的棍子上每边创建的不同类型三角形的数量。计算锐角三角形、直角三角形和钝角三角形的数量

输入格式: 第一行包含N。 第二行包含N个整数。第i个数字表示Ai

约束条件:

For full score: 3≤N≤5000
For 40% score: 3≤N≤500
6    
2 3 9 10 12 15
2 1 4
对于所有测试用例

1≤A[i]≤10^4
A[i]<A[i+1] where 1≤i<N
acute = 0
right = 0
obtuse = 0
a = sorted(a)  # copy and convert to a list
a.append(2 * a[-1])  # add a sentinel equal to twice the max
for i in range(len(a) - 3):  # exclude the sentinel
    if a[i] <= 0:
        continue
    ka = i + 2
    kr = i + 2
    ko = i + 2
    for j in range(i + 1, len(a) - 2):  # i < j, exclude the sentinel
        ka = max(ka, j + 1)
        while a[i] ** 2 + a[j] ** 2 > a[ka] ** 2:
            ka += 1
        acute += ka - (j + 1)
        kr = max(kr, ka)
        while a[i] ** 2 + a[j] ** 2 == a[kr] ** 2:
            kr += 1
        right += kr - ka
        ko = max(ko, kr)
        while a[i] + a[j] > a[ko]:
            ko += 1
        obtuse += ko - kr
输出:

For full score: 3≤N≤5000
For 40% score: 3≤N≤500
6    
2 3 9 10 12 15
2 1 4
可能的三角形是:

For full score: 3≤N≤5000
For 40% score: 3≤N≤500
6    
2 3 9 10 12 15
2 1 4
锐角三角形 10−12−15, 9−10−十二,

直角三角形 9−12−十五

钝角三角形 2.−9−10, 3−9−10, 3−10−12, 9−10−十五

我想知道一种更有效的方法来解决这个问题,这样我就可以在给定的n(~5000)时限内执行它。
在我试图找到复杂性之后,我提出了O(n^3)。我不擅长处理复杂问题。我可能错了。我想用一种更有效的方法来解决这个问题。

您可以通过以下方式来改进该方法:首先,按棒的长度对所有棒进行排序。之后,迭代每对棒(即具有平方复杂度的双循环)。对于每一对,执行一次搜索,以找到从锐角三角形切换到直角三角形的棍棒阵列中的位置(考虑预选的两个棍棒和作为基础的第三个棍棒)。然后执行另一个二进制操作,以找到将形状向右转换为钝角三角形的位置。在此之后,您将不得不执行另一个二进制搜索,以找到第三根棍子太长以至于无法与其形成有效三角形的位置。你将不得不处理一个以上的情况-如果没有直角三角形,你从锐角直接切换到钝角(这可以通过添加一个if来实现)

重要的是要注意,三角形的类型是由与三角形最大边相对的角度来确定的,因此在上述算法中,你只应该考虑比两个预先选定的杆大的边长(可以用另一个二进制来完成)。
总的来说,我提出的方法的复杂性为O(N2*log(N)),这比您的算法要好。

目前我没有看到降低复杂性的方法,但您可以对代码进行一些加速

  • 预先计算
    A[i]
    的平方,而不是反复计算它们
  • 如果按照示例中的顺序对长度进行排序(如果没有排序),则可以在第一次违反条件
    A[i]+A[j]>A[k]
    时退出while循环
  • n-1
    n-2
    的值存储在变量中,而不是反复计算它们(可能已经由编译器优化)
  • 不要计算
    square(A[i])+square(A[j])
    两次,将结果存储在变量中
  • 更改检查条件的顺序。直角三角形的可能性较小。总是先检查最常见的情况
  • 对于整数值,使用
    a*a
    可能比使用
    square(a)
在这里您可以看到我的意思(您仍然需要实现TODO部分)

使用系统;
命名空间代码风暴
{
类计数三角形
{
公共静态双正方形(整数x)
{
返回Math.Pow(x,2);
}
静态void Main(字符串[]参数)
{
int n=int.Parse(Console.ReadLine());
字符串[]A_temp=Console.ReadLine().Split(“”);
int[]A=Array.ConvertAll(A_temp,Int32.Parse);
//TODO:对[]排序(如果尚未始终排序)
//TODO:创建平方值的数组E
int[]Asquares=。。。。
int n_m_2=n-2;
int n_m_1=n-1;
int锐=0,右=0,钝=0;
for(int i=0;i
只是一个小小的提示:Math.Pow()计算正方形相当慢。你应该修改你的方法:

public static double square(int x)
{
    return x * x;
}

有两件事几乎肯定会有所改善:

  • 使用
    x*x
    而不是将其转换为双倍,然后调用
    Pow
    ,以加快平方速度

  • i
    计算一次平方,每
    j
    计算一次平方,每
    k
    计算一次平方

  • 可能会改善事情、使事情变得更糟的事情(简介):

  • 处理预排序的数据

  • 计算最终大小的阈值(其他两个正方形的平方根)并与循环中的值进行比较

  • 当两个平方和不是整数平方时,使用不同的循环(没有值可以匹配直角情况)


  • 这可以在时间
    O(N²)
    中解决。如有必要,对尺寸进行逐级排序

    设三角形的边为
    a=a[k]
    b=a[j]
    c=a[i]