CF134B题解

原题

CF134B Pairs of Numbers


思路概述

题意分析

给定一个初始值为 \((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;
	}	
}
posted @ 2022-05-23 16:56  UOB  阅读(66)  评论(0)    收藏  举报