确定算法的确切执行次数
Determining the exact number of executions of an algorithm
我有这样的算法:
for(int i=1; i<=n; i++)
for(int j=1; j<=2*n; j=j+2)
for(int k=i; k<=j; k++)
instr;
我需要找到一个公式来确定“instr”指令将被执行多少次。
这是我写的。 。但我得到了错误的价值观。例如,对于 n=4,“instr”将执行 43 次,但我从总和中得到 40 次。
我哪里搞砸了?
来自代码
int count = 0;
for(int i=1; i<=n; i++)
for(int j=1; j<=2*n; j=j+2)
for(int k=i; k<=j; k++)
count++;
可以将其转换为语义等价物:
int count = 0;
for(int i=1; i<=n; i++)
for(int j=1; j<=n; j++)
for(int k=i; k<=2*j - 1; k++)
count++;
如果在两个代码版本的末尾打印 count
变量,其值将是:
| loop 1 | loop 2
________________________________
N = 1 | 1 | 1
N = 2 | 6 | 6
N = 3 | 19 | 19
N = 4 | 43 | 43
N = 5 | 82 | 82
您从第二个循环中提取了公式:
这在论文中是有道理的,但是,有一个问题。将您的公式转换为代码:
public static int third_loop(int n ){
int count = 0;
for(int i=1; i<=n; i++)
for(int j=1; j<=n; j++)
count += (2 * j - 1) - i + 1;
return count;
}
并显示变量的值 count
:
| loop 1 | loop 2 | loop 3
____________________________________
N = 1 | 1 | 1 | 1
N = 2 | 6 | 6 | 6
N = 3 | 19 | 19 | 18
N = 4 | 43 | 43 | 40
N = 5 | 82 | 82 | 75
count
值现在不同了,原因是会有迭代,其中 (2 * j - 1) < i + 1,因此公式 (2 * j - 1) - i + 1 将产生负结果,并将这些结果添加到变量 count
。在第二个循环中隐含地避免了一些事情。如果将第三个循环更改为:
public static int fourth_loop(int n ){
int count = 0;
for(int i=1; i<=n; i++)
for(int j=1; j<=n; j++)
count += Math.max((2 * j - 1) - i + 1, 0);
return count;
}
一个人会得到:
| loop 1 | loop 2 | loop 3 | loop 4
__________________________________________
N = 1 | 1 | 1 | 1 | 1
N = 2 | 6 | 6 | 6 | 6
N = 3 | 19 | 19 | 18 | 19
N = 4 | 43 | 43 | 40 | 43
N = 5 | 82 | 82 | 75 | 82
所以你的公式的问题在于它也在考虑负值,而你的代码不是。因为,我没有数学工具来为您提供精确的公式,所以我请您 math.stackexchange 的朋友这样做。
编辑: 从我提供的赏金中,Matthew Towers 得出以下精确表达式:
我有这样的算法:
for(int i=1; i<=n; i++)
for(int j=1; j<=2*n; j=j+2)
for(int k=i; k<=j; k++)
instr;
我需要找到一个公式来确定“instr”指令将被执行多少次。
这是我写的。
我哪里搞砸了?
来自代码
int count = 0;
for(int i=1; i<=n; i++)
for(int j=1; j<=2*n; j=j+2)
for(int k=i; k<=j; k++)
count++;
可以将其转换为语义等价物:
int count = 0;
for(int i=1; i<=n; i++)
for(int j=1; j<=n; j++)
for(int k=i; k<=2*j - 1; k++)
count++;
如果在两个代码版本的末尾打印 count
变量,其值将是:
| loop 1 | loop 2
________________________________
N = 1 | 1 | 1
N = 2 | 6 | 6
N = 3 | 19 | 19
N = 4 | 43 | 43
N = 5 | 82 | 82
您从第二个循环中提取了公式:
这在论文中是有道理的,但是,有一个问题。将您的公式转换为代码:
public static int third_loop(int n ){
int count = 0;
for(int i=1; i<=n; i++)
for(int j=1; j<=n; j++)
count += (2 * j - 1) - i + 1;
return count;
}
并显示变量的值 count
:
| loop 1 | loop 2 | loop 3
____________________________________
N = 1 | 1 | 1 | 1
N = 2 | 6 | 6 | 6
N = 3 | 19 | 19 | 18
N = 4 | 43 | 43 | 40
N = 5 | 82 | 82 | 75
count
值现在不同了,原因是会有迭代,其中 (2 * j - 1) < i + 1,因此公式 (2 * j - 1) - i + 1 将产生负结果,并将这些结果添加到变量 count
。在第二个循环中隐含地避免了一些事情。如果将第三个循环更改为:
public static int fourth_loop(int n ){
int count = 0;
for(int i=1; i<=n; i++)
for(int j=1; j<=n; j++)
count += Math.max((2 * j - 1) - i + 1, 0);
return count;
}
一个人会得到:
| loop 1 | loop 2 | loop 3 | loop 4
__________________________________________
N = 1 | 1 | 1 | 1 | 1
N = 2 | 6 | 6 | 6 | 6
N = 3 | 19 | 19 | 18 | 19
N = 4 | 43 | 43 | 40 | 43
N = 5 | 82 | 82 | 75 | 82
所以你的公式的问题在于它也在考虑负值,而你的代码不是。因为,我没有数学工具来为您提供精确的公式,所以我请您 math.stackexchange 的朋友这样做。
编辑: 从我提供的赏金中,Matthew Towers 得出以下精确表达式: