【dfs版本 和 bfs版本】Educational Codeforces Round 129 (Div. 2), problem: (D) Required Length

题目

 

题意

已知n和x,可以对整数x执行多个操作。

操作:选择在x出现过的任何数字y(y只有1位数),然后用x替换x⋅y

你想使x的十进制表示长度(不带前导零)等于n。要做到这一点,最少需要多少操作?

如果不可能,则为-1。

两种方法对比

其实此题更适合用bfs,保证第一次都出来的就是最小值,不会走太多太多的冤枉路时间,复杂度低;其次,bfs的代码也比较简单与常规,只需要简单标记一下,不去重复之前走过的路。

反观dfs,每一次都走到头,需要遍历所有的方式才能找到最小值;其次,dfs剪枝是个重点,其中需要涉及到数学中的log运算。解决了这一点的话,dfs也蛮简单的。

说一下一些小知识的收获

1.  to_string(x).size()  //可以求出数字x的长度,很方便 

2.  本题所求需要一直比较是否x达到n位,简化一下就是x>=pow(10,n-1) 

3.  log(x1) 除 log(x2) = log以(x2)为底(x1)的对数

4.  数少的时候,用一个数的二进制标记也好帅的。


dfs方法

题解

讲一下这个式子 timee+ 1 + log(tar/x)/log(9)  

timee是到现在为止已经操作的次数。

log(tar/x)/log(9)  是当前x成为tar所需要至少至少的操作数(为什么是至少,因为是以9为底,即假设每次都是乘以9)。

+1是因为log那位出来的基本上都是小数,打了几次表没出现过整数,抱着进位的思想,所以加1。

注意:以上少了任意一步都无法剪枝成功

代码

#include <bits/stdc++.h>

using namespace std;

const int N = 2e5+10;
typedef long long LL;

int chushi;
LL n, x,tar;
int res =999999999;

void dfs(LL x, int timee)
{
	if(timee+1 + log((double)tar/x)/log(9)>= res) return;
	if(x >= tar)
	{
		res = min(res, timee);
		return;
	}
	
	LL now = x;
	int s=0;//标记有这个数,这样遍历的时候,就不会走x*出现的数了
	while(now) s |=(1<<(now%10)), now/=10;
	
	for(int i =9; i >= 2; i --)
		if((s>>i) & 1)
			dfs(x*i, timee+1);
	
	return;
}

int main()
{
	cin >> n >> x;
	tar = pow(10,n-1);
	dfs(x,0);
	if(res != 999999999) cout << res<<endl;
	else puts("-1");
    return 0;
}

bfs方法

题解

这个是常规操作,大家记得开long long

代码

#include <iostream>
#include <String>
#include <map>
#include <cmath>
#include <queue>

typedef long long LL;
using namespace std;

int n;
LL x,tar;
map<LL,bool> mp;

int bfs(LL xx, int times)
{
	queue<pair<LL, int>> q;
	q.push({xx, times});
	while(q.size())
	{
		LL t1 = q.front().first;
		int t2 = q.front().second;
		q.pop();
		if(tar <= t1) return t2;//位数达到n了
		
		LL tt1 = t1;
		while(t1)	
		{
			LL now = (t1%10) * tt1;
			if(t1%10>=2 && !mp[now])
				q.push({now, t2+1}), mp[now]=1;
			t1/=10;
		}	
	}
	return -1;
}
int main()
{
	cin >> n >> x;
	tar = pow(10, n-1);
	cout <<bfs(x, 0)<<'\n';
	return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值