【问题标题】:C find all possible sides of a triangle from the perimeterC 从周长找出三角形所有可能的边
【发布时间】:2017-06-21 12:11:20
【问题描述】:

我不断得到 c 的负数,b 只打印 23,a 像它应该的那样循环。当我把它放在周边时,至少输出加起来是 24。我觉得我已经接近了一些愚蠢的逻辑错误。 我的代码如下。

编写一个程序来找出所有边长为整数的三角形和一个用户 指定的周长。您的程序应该找到所有三元组 a、b 和 c,其中 a + b + c 是用户指定的周长值。

  1 #include <stdio.h>
  2 
  3 int main() {
  4     int p, a, b, c;
  5     printf("Enter a perimeter: ");
  6     scanf("%d", &p);
  7 
  8     printf("Triangles with a perimeter: " " %d\n", p);
  9 
 10     for(a = 1; a < p; a++) {
 11         for(b = a;  b < p; b++)
 12             c = p - (a + b);
 13             b = p - (a + c);
 14             a = p - (b + c);
 15 
 16             printf("%d, %d, %d\n",a,b,c);
 17 
 18 }
 19     return 0;
 20 }

我认为这更像是一个面试问题而不是初学者问题。

【问题讨论】:

  • 寻求调试帮助的问题(“为什么这段代码不起作用?”)必须包括所需的行为、特定的问题或错误以及在问题本身中重现它所需的最短代码。没有明确问题陈述的问题对其他读者没有用处。请参阅:如何创建最小、完整和可验证的示例。
  • 要在数学上得到正确的答案,您还需要考虑triangle inequality
  • 你需要在你的内循环周围放括号,现在外循环有它们
  • 此外,整数长度几乎可以保证 b 和 c 至少为 1。因此您可以稍微缩短循环。
  • 您还应该考虑到a + b 不能短于c。比如p=24,当a=1b=1时,即使c=24-(1+1)也不能是三角形。想象一个有1122 边的三角形?

标签: c


【解决方案1】:

原始代码中有几处错误。有些与什么使三角形成为三角形有关,有些是基本逻辑出了问题。

for (a = 1; a &lt; p; a++) 是错误的,因为三角形的一侧不能超过周长的一半。即使在周长的一半处,也会形成 2 条线,而不是三角形。

for (b = 1; b &lt; (p - a); b++) 是错误的,因为a+b 在开始时会小于周长的一半。

c 是根据pab 的值计算得出的。

c = p - (a + b);

计算ba 有什么意义?

b = p - (a + c);
a = p - (b + c);

正如Jonathan Leffler 指出的那样,代码应该只打印唯一的三角形。这可以通过在printf 语句之前添加条件a&lt;=b &amp;&amp; b&lt;=c 轻松实现。

感谢@JonathanLeffler 抽出时间来调试这段简短的代码。由于b 被初始化为更高的值,并且内部 for 循环条件过早终止循环,导致代码跳过一些输出。

这是代码的更正版本。

#include <stdio.h>
int main() {
    int p, a, b, c;
    printf("Enter a perimeter: ");
    scanf("%d", &p);

    printf("Triangles with a perimeter: " " %d\n", p);

    for (a = 1; 2*a < p; a++) {
        for (b = 1; a+b < p; b++)
            if ((p-2*a) > 0 && (p-2*b) > 0 && (2*a+2*b-p) > 0) {
                c = p - (a + b);
                if(a<=b && b<=c)
                    printf("%d, %d, %d\n", a ,b, c);
            }
    }
    return 0;
}

现在让我们试试吧。

Enter a perimeter: 6
Triangles with a perimeter:  6
2, 2, 2

没错。周长为6 的三角形只有1 可能的组合。 1, 1, 4 单位长边不是三角形,除非您愿意弯曲 4 单位长边。

Enter a perimeter: 12
Triangles with a perimeter:  12
2, 5, 5
3, 4, 5
4, 4, 4

【讨论】:

  • 很好的答案!我不是从几何和三角规则的角度来考虑它,只是根据提问者提供的内容进行编程,但这是非常好的工作。谢谢!
  • 这段代码更符合逻辑。我想你可以说我还是个初学者。我得做更多的练习题。
  • 我之前建议,通过在printf() 之前添加条件if (a &lt;=b &amp;&amp; b &lt;= c) 来获取结果,可以确保每个长度组合只生成一次。我注意到,例如,当 p = 12 时,您会得到:(2, 5, 5)(3, 4, 5)(4, 4, 4) 作为输出。我错过的是p = 11,添加条件省略(3, 5, 3)(因为代码不会生成(3, 3, 5),原因我无法理解)。所以,这个条件还不够好——它确实消除了很多重复的条目(好),但确实丢弃了一些非重复的条目(坏)。
  • @JonathanLeffler - 感谢您发现此错误。难以捉摸的3, 3, 5 是由b 的初始值设置为(p-a)/2(即4)引起的,实际上跳过了3, 3, 5。其他一些排列也被跳过,因为(p-2*a) &gt; 0 &amp;&amp; (p-2*b) &gt; 0 &amp;&amp; (2*a+2*b-p) &gt; 0 导致内部 for 循环过早终止。我将修改并添加您的建议,以将打印输出限制为唯一的三角形。
【解决方案2】:

输出中的重复信息

alvits 当前接受的answer 会生成大量重复输出,其中组合是相同边组合的排列。我修改了代码以打印周长从 3 到 29 的所有三角形,并在打印操作之前添加了建议的条件 if (a &lt;= b &amp;&amp; b &lt;= c)

tp17.c

注意:代码不正确。

#include <stdio.h>

int main(void)
{
    int p, a, b, c;
    // printf("Enter a perimeter: ");
    // scanf("%d", &p);
    for (p = 3; p < 30; p++)
    {
        printf("Triangles with perimeter: %d\n", p);

        for (a = 1; 2 * a < p; a++)
        {
            for (b = (p - a) / 2; (p - 2 * a) > 0 && (p - 2 * b) > 0 && (2 * a + 2 * b - p) > 0; b++)
            {
                c = p - (a + b);
                if (a <= b && b <= c)
                    printf("%d, %d, %d\n", a, b, c);
            }
        }
    }
    return 0;
}

结果的printf() 之前的条件if (a &lt;=b &amp;&amp; b &lt;= c) 旨在确保您只生成每个长度组合一次。我注意到,例如,当 p = 12 时,您会得到:(2, 5, 5)(3, 4, 5)(4, 4, 4) 作为输出。我错过的是p = 11,添加条件省略(3, 5, 3)(因为代码不会生成(3, 3, 5),原因我无法理解)。所以,条件不够好——它确实消除了很多重复的条目(好),但也丢弃了一些非重复的条目(坏)。

因此,代码应该消除条件,这会使程序产生大量冗余输出,大大复杂输出比较。

tp13.c

我还创建了一个密切相关的程序,从相同的基础开始:

#include <stdio.h>

int main(void)
{
    for (int p = 3; p < 30; p++)
    {
        printf("Triangles with perimeter: %d\n", p);
        for (int a = 1; a <= p / 2; a++)
        {
            for (int b = 1; b + a < p; b++)
            {
                int c = p - (a + b);
                if (a + b <= c || a + c <= b || b + c <= a)
                    continue;
                if (a <= b && b <= c)
                    printf("%d, %d, %d\n", a, b, c);
            }
        }
    }
    return 0;
}

输出比较

比较tp13tp17 输出的部分diff -u 输出是:

 Triangles with perimeter: 11
 1, 5, 5
 2, 4, 5
-3, 3, 5
+2, 5, 4
 3, 4, 4
+3, 5, 3
+4, 3, 4
+4, 4, 3
+4, 5, 2
+5, 3, 3
+5, 4, 2
+5, 5, 1
 Triangles with perimeter: 12
 2, 5, 5
 3, 4, 5
+3, 5, 4
 4, 4, 4
+4, 5, 3
+5, 3, 4
+5, 4, 3
+5, 5, 2
 Triangles with perimeter: 13

查看 12 周长的结果,很明显tp17 只是生成不同的排列。但是,查看周长 11 的结果表明 tp17 生成 (3, 5, 3)(5, 3, 3) 但不是 (3, 3, 5)tp13 生成 (3, 3, 5) 而不是其他两个排列。但是,显示的输出片段中tp17 的输出中的所有其他额外行都是其他行的排列。

需要不同的输出格式

上面的输出格式不适合自动比较,所以我修改了输出以打印周长,然后是按非递减顺序列出的三个边。因此,我在tp17.c 中添加了代码,以便在打印前将边排序为非递减顺序。对于三个元素,可能有更简单的方法,但这是可行的。

tp47.c

/* SO 4203-5818 - Calculate all triangles with given perimeter */
#include <stdio.h>
#include <stdlib.h>

static int int_cmp(const void *va, const void *vb)
{
    int a = *(int *)va;
    int b = *(int *)vb;
    return (a > b) - (a < b);
}

int main(void)
{
    int p, a, b, c;
    for (p = 3; p < 30; p++)
    {
        for (a = 1; 2 * a < p; a++)
        {
            for (b = (p - a) / 2; (p - 2 * a) > 0 && (p - 2 * b) > 0 && (2 * a + 2 * b - p) > 0; b++)
            {
                c = p - (a + b);
                {
                int d[] = { a, b, c };
                qsort(d, 3, sizeof(d[0]), int_cmp);
                printf("%d: %d, %d, %d\n", p, d[0], d[1], d[2]);
                }
            }
        }
    }
    return 0;
}

tp43.c

/* SO 4203-5818 - Calculate all triangles with given perimeter */

#include <stdio.h>

int main(void)
{
    for (int p = 3; p < 30; p++)
    {
        for (int a = 1; a <= p / 2; a++)
        {
            for (int b = 1; b + a < p; b++)
            {
                int c = p - (a + b);
                if (a + b <= c || a + c <= b || b + c <= a)
                    continue;
                if (a <= b && b <= c)
                    printf("%d: %d, %d, %d\n", p, a, b, c);
            }
        }
    }
    return 0;
}

(除打印外,与tp13.c相同。)

比较

现在可以对输出进行排序和比较。 tp43-u 选项是多余但对称的。

$ tp43 | sort -u -k1n -k2n -k3n -k4n > tp43.out
$ tp47 | sort -u -k1n -k2n -k3n -k4n > tp47.out
$ diff tp43.out tp47.out
$ 

因此,唯一的输出是相同的,但是当您计算差异时,tp47 的输出中有 390 行额外的行:

$ tp43 | sort -k1n -k2n -k3n -k4n > tp43-all.out
$ tp47 | sort -k1n -k2n -k3n -k4n > tp47-all.out
$ diff tp43-all.out tp47-all.out | diffcount
deleted 0, inserted 390
$ wc -l tp4?.out tp4?-all.out
     206 tp43.out
     206 tp47.out
     206 tp43-all.out
     596 tp47-all.out
    1214 total
$

仅作记录,文件tp43.outtp47.outtp43-all.out 是相同的。他们的内容是:

3: 1, 1, 1
5: 1, 2, 2
6: 2, 2, 2
7: 1, 3, 3
7: 2, 2, 3
8: 2, 3, 3
9: 1, 4, 4
9: 2, 3, 4
9: 3, 3, 3
10: 2, 4, 4
10: 3, 3, 4
11: 1, 5, 5
11: 2, 4, 5
11: 3, 3, 5
11: 3, 4, 4
12: 2, 5, 5
12: 3, 4, 5
12: 4, 4, 4
13: 1, 6, 6
13: 2, 5, 6
13: 3, 4, 6
13: 3, 5, 5
13: 4, 4, 5
14: 2, 6, 6
14: 3, 5, 6
14: 4, 4, 6
14: 4, 5, 5
15: 1, 7, 7
15: 2, 6, 7
15: 3, 5, 7
15: 3, 6, 6
15: 4, 4, 7
15: 4, 5, 6
15: 5, 5, 5
16: 2, 7, 7
16: 3, 6, 7
16: 4, 5, 7
16: 4, 6, 6
16: 5, 5, 6
17: 1, 8, 8
17: 2, 7, 8
17: 3, 6, 8
17: 3, 7, 7
17: 4, 5, 8
17: 4, 6, 7
17: 5, 5, 7
17: 5, 6, 6
18: 2, 8, 8
18: 3, 7, 8
18: 4, 6, 8
18: 4, 7, 7
18: 5, 5, 8
18: 5, 6, 7
18: 6, 6, 6
19: 1, 9, 9
19: 2, 8, 9
19: 3, 7, 9
19: 3, 8, 8
19: 4, 6, 9
19: 4, 7, 8
19: 5, 5, 9
19: 5, 6, 8
19: 5, 7, 7
19: 6, 6, 7
20: 2, 9, 9
20: 3, 8, 9
20: 4, 7, 9
20: 4, 8, 8
20: 5, 6, 9
20: 5, 7, 8
20: 6, 6, 8
20: 6, 7, 7
21: 1, 10, 10
21: 2, 9, 10
21: 3, 8, 10
21: 3, 9, 9
21: 4, 7, 10
21: 4, 8, 9
21: 5, 6, 10
21: 5, 7, 9
21: 5, 8, 8
21: 6, 6, 9
21: 6, 7, 8
21: 7, 7, 7
22: 2, 10, 10
22: 3, 9, 10
22: 4, 8, 10
22: 4, 9, 9
22: 5, 7, 10
22: 5, 8, 9
22: 6, 6, 10
22: 6, 7, 9
22: 6, 8, 8
22: 7, 7, 8
23: 1, 11, 11
23: 2, 10, 11
23: 3, 9, 11
23: 3, 10, 10
23: 4, 8, 11
23: 4, 9, 10
23: 5, 7, 11
23: 5, 8, 10
23: 5, 9, 9
23: 6, 6, 11
23: 6, 7, 10
23: 6, 8, 9
23: 7, 7, 9
23: 7, 8, 8
24: 2, 11, 11
24: 3, 10, 11
24: 4, 9, 11
24: 4, 10, 10
24: 5, 8, 11
24: 5, 9, 10
24: 6, 7, 11
24: 6, 8, 10
24: 6, 9, 9
24: 7, 7, 10
24: 7, 8, 9
24: 8, 8, 8
25: 1, 12, 12
25: 2, 11, 12
25: 3, 10, 12
25: 3, 11, 11
25: 4, 9, 12
25: 4, 10, 11
25: 5, 8, 12
25: 5, 9, 11
25: 5, 10, 10
25: 6, 7, 12
25: 6, 8, 11
25: 6, 9, 10
25: 7, 7, 11
25: 7, 8, 10
25: 7, 9, 9
25: 8, 8, 9
26: 2, 12, 12
26: 3, 11, 12
26: 4, 10, 12
26: 4, 11, 11
26: 5, 9, 12
26: 5, 10, 11
26: 6, 8, 12
26: 6, 9, 11
26: 6, 10, 10
26: 7, 7, 12
26: 7, 8, 11
26: 7, 9, 10
26: 8, 8, 10
26: 8, 9, 9
27: 1, 13, 13
27: 2, 12, 13
27: 3, 11, 13
27: 3, 12, 12
27: 4, 10, 13
27: 4, 11, 12
27: 5, 9, 13
27: 5, 10, 12
27: 5, 11, 11
27: 6, 8, 13
27: 6, 9, 12
27: 6, 10, 11
27: 7, 7, 13
27: 7, 8, 12
27: 7, 9, 11
27: 7, 10, 10
27: 8, 8, 11
27: 8, 9, 10
27: 9, 9, 9
28: 2, 13, 13
28: 3, 12, 13
28: 4, 11, 13
28: 4, 12, 12
28: 5, 10, 13
28: 5, 11, 12
28: 6, 9, 13
28: 6, 10, 12
28: 6, 11, 11
28: 7, 8, 13
28: 7, 9, 12
28: 7, 10, 11
28: 8, 8, 12
28: 8, 9, 11
28: 8, 10, 10
28: 9, 9, 10
29: 1, 14, 14
29: 2, 13, 14
29: 3, 12, 14
29: 3, 13, 13
29: 4, 11, 14
29: 4, 12, 13
29: 5, 10, 14
29: 5, 11, 13
29: 5, 12, 12
29: 6, 9, 14
29: 6, 10, 13
29: 6, 11, 12
29: 7, 8, 14
29: 7, 9, 13
29: 7, 10, 12
29: 7, 11, 11
29: 8, 8, 13
29: 8, 9, 12
29: 8, 10, 11
29: 9, 9, 11
29: 9, 10, 10

【讨论】:

    猜你喜欢
    • 2023-01-30
    • 2023-01-31
    • 2014-05-14
    • 1970-01-01
    • 1970-01-01
    • 2019-10-06
    • 2017-11-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多