CF134B题解
原题
思路概述
题意分析
给定一个初始值为 \((1,1)\) 的有序数对和 \(n∈N^*\) ,规定每次能执行操作 \((a,b)→(a+b,b) \text{ or } (a,b)→(a,a+b)\) ,求该数对操作到满足 \(a=n \text{ or } b=n\) 的最小步数。
思路分析
操作方式太原始,直接考虑DFS。但一个数对 \((a,b)\) 满足其中一个等于 \(n\) 的状态数太多,故考虑反向搜索,从 \((n,k)(k∈N^*)\) 搜回 \((1,1)\) 。
算法实现
关于反向搜索
首先讨论反向搜索的正确性。由于题目要求构造一种从 \((1,1)\) 转移到 \((n,k)(k∈N^*)\) 的操作方案并求最小步数,再考虑操作方式,不难得出:对于除 \(n\) 外的另一个数 \(k\) ,其大小与步数始终呈正相关关系。所以在满足步数最小的情况下, \(k\) 的值必然在区间 \([1,n]\) 内(若 \(k>n\) ,则数对 \((n,k)\) 必然由 \((n,k-n)\) 转移而来,则当前求出数对所需操作数不是最小值)。
关于搜索
正常深度优先搜索算法结构,终止条件为 \(x=1 \text{ and } y=1\) 。主函数中枚举 \((n,k)(k=1,2,3...n)\) 即可。
if(x==1 && y==1)
{
minimum=s;
return;
}
else
{
if(x>y) dfs(x-y,y,s+1);
else dfs(x,y-x,s+1);
return;
}
简单剪枝技巧
对于搜索过程中出现的步数 \(s\) 大于当前纪录最小步数最小值 \(minimum\) ,直接返回,可优化部分无效搜索。
AC code
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<queue>
#include<set>
#include<ctime>
#define RI register int
using namespace std;
int n,minimum=0x3f3f3f3f;
inline int read();/*快读(板子自带)*/
inline void print(int x);/*快输(板子自带)*/
inline void dfs(int x,int y,int s);/*DFS 但是逆向搜索*/
int main()
{
n=read();
for(RI i=1;i<=n;++i) dfs(n,i,0);
print(minimum);
return 0;
}
inline int read(void)
{
char putin;bool isneg=false;RI ret=0;
putin=getchar();
while((putin>'9' || putin<'0') && putin!='-')
putin=getchar();
if(putin=='-')
{
isneg=true;
putin=getchar();
}
while(putin>='0' && putin<='9')
{
ret=(ret<<3)+(ret<<1)+(putin&15);
putin=getchar();
}
return isneg?-ret:ret;
}
inline void print(int x)
{
if(x<0)
{
putchar('-');
x=-x;
}
if(x>9) print(x/10);
putchar(x%10+'0');
return;
}
inline void dfs(int x,int y,int s)
{
if(s>minimum) return;/*简单剪枝操作 若当前操作步数已经超过记录的最小值 则直接停止搜索*/
else if(x==1 && y==1)/*搜到x=1,y=1的情况 搜索终止 开始回溯*/
{
minimum=s;
return;
}
else
{
if(x>y) dfs(x-y,y,s+1);
else dfs(x,y-x,s+1);
return;
}
}
浙公网安备 33010602011771号