题目大意:
对于一个数字对
(a,b)
(
a
,
b
)
,可以将其变为新数字对
(a+b,b)
(
a
+
b
,
b
)
或
(a,a+b)
(
a
,
a
+
b
)
。
给定一正整数n,问最少需要多少次操作可将数字对
(1,1)
(
1
,
1
)
变为一个数字对,且该数字对有一个为n。
思路:
真的不会做啊。。。
考试时想了
bfs
b
f
s
,
dfs
d
f
s
,
DP
D
P
,但是都至少是
O(n2)
O
(
n
2
)
的算法,对于
n≤106
n
≤
10
6
根本吃不消。
最后还是打了一个
DP
D
P
灰溜溜的交上去,30分。
正解:数论, GCD G C D
有谁看得出这是
GCD
G
C
D
的题目???
对于给定的
n
n
,我们可以枚举所有的,模拟还原
(n,i)
(
n
,
i
)
,最终步数最少的就是最终解。
这道题可以类比求
gcd
g
c
d
的辗转相除法。
若
a>b
a
>
b
,则
gcd(a,b)=gcd(amodb,b)
g
c
d
(
a
,
b
)
=
g
c
d
(
a
m
o
d
b
,
b
)
若
a≤b
a
≤
b
,则
gcd(a,b)=(a,bmoda)
g
c
d
(
a
,
b
)
=
(
a
,
b
m
o
d
a
)
当达到一定次数时,
b=1
b
=
1
,那么这就是一个合法的解。如果
b=0
b
=
0
时,
b
b
没有等于过,那么这个解就不合法。
代码:
#include <cstdio>
#include <iostream>
using namespace std;
int n,ans;
int gcd(int a,int b) //辗转相除法
{
if (!b) return 99999999; //b到达0且没有等于过1,无解
if (b==1) return a-1; //b=1,有借
return gcd(b,a%b)+a/b;
}
int main()
{
scanf("%d",&n);
ans=99999999;
for (int i=1;i<=(n+1)/2+1;i++) //简单精简。
ans=min(ans,gcd(n,i));
return printf("%d\n",ans)&0;
}