我们假设我们有一对数字(a,b)。我们可以在一步中从给定对中获得一对新的(a + b,b)或(a,a + b)。
让初始数字对为(1,1)。我们的任务是找到数字k,即,将(1,1)转换为至少一个数等于n的对中所需的最少步骤数。 我通过找到所有可能的对来解决它,然后返回给定数字形成的最小步骤,但是它需要相当长的时间来计算。我猜这必须以某种方式与查找gcd.can有关,请帮助或提供给我这个概念的一些链接。 这是解决这个问题的程序,但对我来说并不聪明......
#include <iostream>
using namespace std;
#define INF 1000000000
int n,r=INF;
int f(int a,int b){
if(b<=0)return INF;
if(a>1&&b==1)return a-1;
return f(b,a-a/b*b)+a/b;
}
int main(){
cin>>n;
for(int i=1;i<=n/2;i++){
r=min(r,f(n,i));
}
cout<<(n==1?0:r)<<endl;
}
答案 0 :(得分:1)
我解决这些问题的方法(我从projecteuler.net得到的)是计算序列的前几个项,然后在oeis中搜索具有相同项的序列。这可以导致解决方案的数量级更快。在你的情况下,序列可能是:http://oeis.org/A178031但不幸的是它没有易于使用的公式。 : 由于n的约束相对较小,因此可以从(1,1)到达对(a,b)所需的最小步数执行dp。你得到一个二维数组,存储给定对的答案,然后你做一个带有memoization的递归:
int mem[5001][5001];
int solve(int a, int b) {
if (a == 0) {
return mem[a][b] = b + 1;
}
if (mem[a][b] != -1) {
return mem[a][b];
}
if (a == 1 && b == 1) {
return mem[a][b] = 0;
}
int res;
if (a > b) {
swap(a,b);
}
if (mem[a][b%a] == -1) { // not yet calculated
res = solve(a, b%a);
} else { // already calculated
res = mem[a][b%a];
}
res += b/a;
return mem[a][b] = res;
}
int main() {
memset(mem, -1, sizeof(mem));
int n;
cin >> n;
int best = -1;
for (int i = 1; i <= n; ++i) {
int temp = solve(n, i);
if (best == -1 || temp < best) {
best = temp;
}
}
cout << best << endl;
}
事实上在这种情况下,dp和BFS之间没有太大差异,但这是解决此类问题的一般方法。希望这会有所帮助。
编辑:如果a为零,则在dp中返回足够大的值
答案 1 :(得分:0)
您可以使用广度优先搜索算法来执行此操作。在每一步中,您都会生成以前未见过的所有可能的NEXT步骤。如果接下来的步骤包含结果,那么如果不重复则完成。重复此操作的次数是最小转换次数。
答案 2 :(得分:0)
首先,k-3步后你可以得到的最大数是kth fibinocci数。设t为魔术比率。
现在,n开始于(n,upper(n / t))。
If x>y:
NumSteps(x,y) = NumSteps(x-y,y)+1
Else:
NumSteps(x,y) = NumSteps(x,y-x)+1
迭代计算NumSteps(n,upper(n / t))
PS:使用upper(n / t)可能并不总能提供最佳解决方案。您可以围绕此值进行一些本地搜索,以获得最佳结果。为了确保最优性,您可以尝试从0到n-1的所有值,其中最坏情况复杂度为O(n ^ 2)。但是,如果最佳值来自接近上限(n / t)的值,则解为O(nlogn)