Starting with x and repeatedly multiplying by x, we can compute x31 with thirty multiplications:
x2 = x x x, x3 = x2 x x, x4 = x3 x x, ... , x31 = x30 x x.The operation of squaring can appreciably shorten the sequence of multiplications. The following is a way to compute x31 with eight multiplications:
x2 = x x x, x3 = x2 x x, x6 = x3 x x3, x7 = x6 x x, x14 = x7 x x7,This is not the shortest sequence of multiplications to compute x31 . There are many ways with only seven multiplications. The following is one of them:
x15 = x14 x x, x30 = x15 x x15, x31 = x30 x x.
x2 = x x x, x4 = x2 x x2, x8 = x4 x x4, x10 = x8 x x2,There however is no way to compute x31 with fewer multiplications. Thus this is one of the most efficient ways to compute x31 only by multiplications.
x20 = x10 x x10, x30 = x20 x x10, x31 = x30 x x.
If division is also available, we can find a shorter sequence of operations. It is possible to compute x31 with six operations (five multiplications and one division):
x2 = x x x, x4 = x2 x x2, x8 = x4 x x4, x16 = x8 x x8, x32 = x16 x x16, x31 = x32 ÷ x.This is one of the most efficient ways to compute x31 if a division is as fast as a multiplication.
Your mission is to write a program to find the least number of operations to compute xn by multiplication and division starting with x for the given positive integer n. Products and quotients appearing in the sequence of operations should be x to a positive integer's power. In other words, x-3, for example, should never appear.
Input
The input is a sequence of one or more lines each containing a single integer n. n is positive and less than or equal to 1000. The end of the input is indicated by a zero.
Output
Your program should print the least total number of multiplications and divisions required to compute xn starting with x for the integer n. The numbers should be written each in a separate line without any superfluous characters such as leading or trailing spaces.
Sample Input
1 31 70 91 473 512 811 953 0
Sample Output
0 6 8 9 11 9 13 12
#include <cstdio> #include <cstring> #include <cmath> using namespace std; long long array[1200]; int array_count = 0; int n; bool dfs_search(int now_d, int max_d); int main() { while(scanf("%d", &n) && n != 0) { memset(array, 0, sizeof(array)); array[0] = 1; array_count = 0; array_count++; if(n == 1) { printf("0\n"); continue; } else if(n == 2) { printf("1\n"); continue; } // 迭代加深搜索 array[1] = 2; array_count++; for(int i = 2; i <= n-1; i++) { // printf("here: %d\n", i); if(dfs_search(1, i)) { printf("%d\n", i); break; } } } return 0; } // 迭代加深搜索 bool dfs_search(int now_d, int max_d) { if(now_d == max_d) { if(array[now_d] == n) return true; else return false; } else { long long max = 0; for(int i = 0; i < array_count; i++) { if(array[i] > max) max = array[i]; } if(pow(2, max_d-now_d)*max < n) return false; } int i = array_count-1; for(int j = 0; j < array_count; j++) { long long new_num1 = array[i]+array[j]; long long new_num2 = abs(array[i]-array[j]); int find_flag1 = 0; int find_flag2 = 0; for(int k = 0; k < array_count; k++) { if(array[k] == new_num1) find_flag1 = 1; if(array[k] == new_num2) find_flag2 = 1; } array[array_count] = new_num1; array_count++; if(dfs_search(now_d+1, max_d)) return true; array_count--; if(new_num2 > 0 && new_num2 != new_num1) { array[array_count] = new_num2; array_count++; if(dfs_search(now_d+1, max_d)) return true; array_count--; } } return false; }
本题是第一道独立完成的迭代加深搜索,鼓励一下!
剪枝是根据得到的最大的数乘以2^(还能搜的层数),如果这个数小于n, 就剪枝。
另外,本题的搜索中每次都只搜索上一层刚刚得到的那个数和其他数的和或差,而不是任取两个数。
原因是:假设最终得到的数为a = b +/- c, 如果b和c都不是倒数第二次得到的数,那么就会有一个序列(除了倒数第二个数不生成,其他和本序列相同),
得到最终的数a,但是长度减小1.同理可证倒数第二个数的生成必定有倒数第三个数来参与。
所以第i次生成的数,必定有第i-1次生成的数来参与生成。
刘汝佳的算法竞赛入门经典(第二版)P210说无法给出证明,不知为何。