【问题标题】:Calculating using modulus [closed]使用模数计算 [关闭]
【发布时间】:2013-09-16 20:14:00
【问题描述】:

我正在解决一个问题: 用户输入 3 个树高以及树高限制。然后程序计算要移除的树的数量。

示例输入:

 Tree1: 14
 Tree2: 7
 Tree3: 16

 Tree limit: 11

样本输出:

 Amount to remove: 8

这对我来说通常不会太糟糕,虽然我还是一个初学者,但问题是,我将在没有 if 语句的情况下计算它。我必须使用模数来计算。我花了很长时间研究和尝试不同的东西,但我似乎无法得到它?有任何想法吗?

【问题讨论】:

  • 你能发布你最好的代码吗?
  • 你还能用ternary语句吗?
  • “没有 if 语句”是什么意思?完全没有分支?你可以使用循环吗?
  • @nos 要删除的数量 = (Tree1 - 11) + (Tree3 - 11)。我们省略了Tree2,因为它是<= 11
  • if 是正确的工具。其他东西都是愚蠢的游戏,对实际学习没什么帮助。

标签: c algorithm operators modular-arithmetic


【解决方案1】:

您要查找的表达式是:

tree[i] % max % tree[i];

tree[i] 大于max 时:
例如:16 和 11

16 % 11 = 5
5 % 16 = 5

但是当tree[i] 小于max 时:
例如:7 和 11

7 % 11 = 7
7 % 7 = 0

int main(void)
{
    int tree[3] = {0};
    int max = 0;
    int cut = 0;

    printf("Max Height: "),
    scanf("%d", &max);

    for(int i=0; i<3; ++i)
    {
        printf("Tree%d: ",i+1),
        scanf("%d", &tree[i]);
    }

    for(int i=0; i<3; ++i)
    {
        cut += (tree[i] % max) % tree[i];
    }
    printf("Amount to remove: %d\n", cut);

    getchar();
    return 0;
}

2015 年 8 月(距离原帖将近 2 年),我决定重新审视这个问题,并提出一个通用的解决方案。

它看起来有点工作,但完整的表达是:

int cut = (tree % max % tree) + !!(tree/max) * (tree/max - 1) * max;

示例:

| Tree | Max | Expression      | Answer |
|    4 |  11 | 0 + 0 * -1 * 11 |      0 |
|   47 |  11 | 3 + 1 * 3 * 11  |     36 |

注意:我使用 !! (double-not) 几乎是 C / C++ 唯一的构造。可能不适用于其他语言。

【讨论】:

  • +1,可能会处理 OP 的情况,但不幸的是,这只适用于tree[i] &gt;= n*max,其中n &gt; 1。答案将包括整数除法 模,但这会将 OP 置于最近的轨道上。
  • 如果tree[i] 是 25 岁,这会起作用吗?你会从模数计算中得到 3 的答案。
  • +1 表示声明 x%max%x。但是修复范围问题的编辑会很好。解决方案中的范围仅适用于 0
  • 2015:我用一个通用的表达方式更新了我的帖子。它总共涉及 4 个术语,和一个双重不。但它没有相同的域问题。
【解决方案2】:

这是一个通用的解决方案:

#include <stdio.h>

#define CUTAMOUNT(tr, lim) (tr - lim) * (((2 * tr) - ((2 * tr) % (tr + lim))) / (tr + lim - 1))

int main (int argc, char **argv) {

    int tree1 = 14;
    int tree2 = 7;
    int tree3 = 16;
    int limit = 11;

    int cutamounttotal = 0;

    cutamounttotal += CUTAMOUNT(tree1, limit);
    cutamounttotal += CUTAMOUNT(tree2, limit);
    cutamounttotal += CUTAMOUNT(tree3, limit);

    printf("Amount to remove: %d\n", cutamounttotal);

    return 0;
}
  • 没有分支
  • 没有循环
  • 无条件
  • 没有三元运算
  • 无位运算
  • 没有逻辑运算

只有算术运算。诀窍是要了解 % 是唯一可以创建步骤的算术运算符。操作数的大小必须适当,以确保该步骤只发生在我们想要的地方,而不是其他地方。然后,我们可以利用该步骤来给出所需的结果。

【讨论】:

  • 完美无瑕!我们说话时很高兴地吃我的话。
【解决方案3】:

您可以只使用绝对值函数(abs)、除法、减法、加法。

Tree1: 14
Tree2: 7
Tree3: 16

Tree limit: 11

14-11=3 ----->3+abs(3)=6  ----------> 6/2 =3
7-11=-4 ----> -4 + abs(-4)=0 -------------> 0/2=0
16-11=5 -----> 5+abs(5)=10 ------------> 10/2 = 5
...
...
...
3+5 = 8 :D

上面的文字显示了如何将较小的值转换为零。因此,只有更大的值才会产生附加效果。

如果你不能使用 abs() 那么你可以左移 + 右移组合来获得绝对值。 但这可能是未定义的行为。结果是针对有符号值的右移实现定义的。

【讨论】:

  • 可能是最一般的答案,但它只是隐藏了abs() 函数中的实现,它仍然必须使用if,或者某种带有位移或条件的技巧。跨度>
  • 并非总是如此,它可以使用 msb 位进行广播或乘法运算。例如,Val * msb.AND.1 就是这个东西。
  • 换句话说,“某种带有位移或条件的技巧”。
  • 是的,我只是找不到确切的摆弄:)
  • 如果我们不能隐藏“if”,别人怎么不能隐藏cpu级别的硬件“if”?左移 1 位和右移 1 位只会使 msb 为零:P
【解决方案4】:

我对自己想了这么多这个问题感到有点失望,但话虽如此,我还是会冒昧地说,对于所有n &gt; 0 都没有通用的解决方案。 t 使用if 语句,或者不使用其他某种诡计来模拟一个。如果有人证明我错了,我会很乐意接受我的话。

对于每棵树,明显且正确的解决方案是:

cut = max(height - limit, 0);

相当于:

if ( height - limit > 0 ) {
   cut = height - limit;
} else {
   cut = 0;
}

或者:

if ( height > limit ) {
   cut = height - limit;
} else {
   cut = 0;
}

在不实际显式使用if 语句的情况下模拟这种情况的最简单方法(使用max() 函数除外)是:

cut = (height - limit) * (height > limit);

因为height &gt; limit 将在正确的时间评估为10

您也可以使用while 循环来模拟它,如下所示:

cut = 0;
while ( height > limit ) {
   cut = height - limit;
   break;
}

并且使用三元运算符是声称不使用if 的最明显的方式。可能还有其他技巧会弄乱位,但故事是一样的。

可以修改这些方法中的任何一种,以根据问题要求使用模运算符,但所取得的成果只是让更简单的算法变得更复杂。

我怀疑 abelenky 答案中的方法是正在寻求的方法,并且可能是该问题的最佳整体解决方案,尽管它仅适用于 0 &lt; n &lt; 2 * limit

【讨论】:

  • +1 最佳解决方案。 cut = (height - limit) * (height &gt; limit)
【解决方案5】:

假设您已经将 3 个树高读入一个数组:

int trees[3];
int limit = 11;
int i;
int cut = 0;
for (i = 0; i < 3; i++) {
    int cut += trees[i] > limit
             ? (trees[i] / limit - 1) * limit + trees[i] % limit
             : 0;
}
printf("Amount to remove: %d\n", cut);

【讨论】:

  • 这将返回需要砍伐的树木数量,而不是要砍伐的总长度。
【解决方案6】:

假设你被允许使用*/&gt;,你可以这样做:

#include <stdio.h>

int main()
{
  int trees[3] = {24, 7, 16};
  int limit = 11;
  int allowedRemainder = 0;
  int mod = 0;
  int modCount = 0;
  int i;
  for (i = 0; i < 3; ++i)
  {
    allowedRemainder = (trees[i] / limit) - 1;
    mod = trees[i] % limit;

    modCount += (allowedRemainder > 0) * (allowedRemainder * limit) +
                (allowedRemainder >= 0) * mod;
    printf("Loop %d: mod = %d\n", i, modCount);
  }
  printf("Amount to remove: %d\n", modCount);
  return 0;
}

(allowedRemainder &gt; 0) * (allowedRemainder * limit) 表示如果我们至少有超过允许的limit,则将limit 的倍数添加到modCount(allowedRemainder &gt;= 0) * mod 表示如果我们有超过 limit,则将剩余部分添加到 modCount

[Sample Code]

【讨论】:

  • 这也只适用于tree[n] &lt; (limit * 2)。例如,如果 tree[0] 是 30,那么您最终会得到 8 * 1
  • @PaulGriffiths:好点,我修复了处理这个问题的逻辑。
【解决方案7】:

[编辑] - 树的所有值的解决方案,使用 % 运算符,但不是三元:

#include <stdio.h>

#define MAX 11

int modsum(int a, int b, int c) ;

int main()
{
    int results;
    results = modsum(25, 7, 16);
    return 0;
}

int modsum(int a, int b, int c)
{
    int i, suma, sumb, sumc;

    i=0;
    while(a > 2*MAX)
    {
        i++;
        a -= MAX;
    }
    suma = (i*MAX)+(a%MAX%a);

    i=0;
    while(b > 2*MAX)
    {
        i++;
        b -= MAX;
    }
    sumb = (i*MAX)+(b%MAX%b);

    i=0;
    while(c > 2*MAX)
    {
        i++;
        c -= MAX;
    }
    sumc = (i*MAX)+(c%MAX%c);


    return suma+sumb+sumc;

}

【讨论】:

  • “a>11 ”与“if staement”有何不同?
  • @MK - 它确实依赖于使用三元运算符,是的,但是 OP 没有回答这样做是否越界。
  • 三元运算符和if是一回事。
  • 查看编辑,为没有三元的树的所有值提供解决方案。
  • 使用while 仍然是作弊,如果if 是不允许的。而不是if ( h &gt; max ) { cut = h - max; } else { cut = 0; },你可以直接使用cut = 0; while ( h &gt; max ) { cut = h - max; break; } 来说明这是一个多么愚蠢的问题。
【解决方案8】:

树的高度在一个数组中,因为我懒得做 3 个变量。
它根据要求使用模运算符。

#include <stdio.h>

int main(void)
{
  int tree_h[]={14,7,16};
  int limit=11;
  int i;
  int remove=0;

  for(i=0;i<3;i++)
  {
    remove+=(tree_h[i]>limit)*(tree_h[i]%limit);
  }
  printf("Amount to remove: %d\n", remove);

  return 0;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-07-04
    • 2012-04-03
    • 1970-01-01
    • 1970-01-01
    • 2012-06-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多