算法学习----DFS----最大数字

本文分析了C++实现的蓝桥杯最大数字问题中的错误,主要在于暴力递归和数据类型的不当选择。作者提出了优化策略,优先级使用操作1提升数字,限制操作2并在递归过程中调整剩余次数,最终给出正确且高效的解决方案。
摘要由CSDN通过智能技术生成

[原题地址](8.最大数字 - 蓝桥云课 (lanqiao.cn))

#错误求解

第一次求解时,完全按照题目的介绍方式暴力求解,从头到尾的遍历了操作1和操作2,导致时间复杂远超出题目要求。

#include <iostream>
#include <vector>
#include<algorithm>
#include<cmath>
using namespace std;

int re=0;
vector<int> ve;
int sum = 0;

int f1(int n){
  if(n>=0 && n<9)   n++;
  else if(n == 9)   n=0;
  return n;
}
int f2(int n){
  if(n>0 && n<=9)   n--;
  else if(n == 0)   n=9;
  return n;
}
"""该方法时间复杂度过大,不断在递归中调用的暴力解法,"""
"""当N,A,B偏大时运行时间过长""" 

bool dfs(int a,int b){
	if(b == 0){
		for(int j=0;j<ve.size();j++){
      	if(a != 0){
      		a--;
      		ve[j] = f1(ve[j]);
      		dfs(a,b);
      		a++;
      		ve[j] = f2(ve[j]);
      	  }
        }
	}
	if(a == 0){
		for(int k=0;k<ve.size();k++){
	      sum += ve[k]*pow(10,k);
	      //cout<<sum<<"\n";   //在求和的过程中,在最后一步会自动将最后一位减1
		  //                   猜测是由于二进制的原因? 
	    }
	    //cout<<sum<<"  "<<re<<"\n";
	    if(sum > re){ 	
	    	re = sum;	
	    }
		sum = 0;
	    return true;
	}
	for(int i=0;i<ve.size();i++){
		if(b != 0){ 
		  b--;		 //使用一次f2之后剩余的机会
		  ve[i] = f2(ve[i]);
		  dfs(a,b);
		  b++;
		  ve[i] = f1(ve[i]);
		}
	}
}

int main()
{
  int N,A,B;
  cin>>N>>A>>B;
  //vector<int> ve;
  while(N!=0){
    ve.push_back(N%10);
    N = N/10;
  }
  dfs(A,B);
  cout<<re+1;
  return 0;
}

#分析原因 + 题目分析

1.首先使用int类型作为输入数和输出数的存储类型,超出了该类型所能存储的最大值。对于题目,应采用long long 类型。

  int的存储大小:4字节的8位可表示数,2^32=42 9496 7296

  long long的存储大小:8字节8位可表达位数,2^64=1844 6744 0737 0960 0000

2.在上述代码中,将每一位数字都进行了操作1和操作2,递归条件是当操作1和操作2和剩余数都为0。实际上进行操作1后,不再对该位的数字进行操作2,不然相当于浪费空间,同时题目并未要求要将操作1和操作2都使用完。

3.题目希望得出最大值,即保障从高位到低位每一位数字尽可能的大。

4.操作1使用加法,我们希望通过操作1将该位的数字提高到尽可能大。此时通过操作1,会有两种可能(设该位数字位x,操作1的数量还有n1个):

(1)n1>=9-x:可以将该位提至9;

(2)n1<9-x :该位最高提至x+n1;

所以,从高到低遍历的过程中,取n1和9-x中的最大值作为该位要增加的值。

5.操作2使用减法,我们只在该位数字可能由0转1时使用,(设该位数字位x,操作2的数量还有n2个)即当n2>x时使用。

6.优先使用操作1,然后进行递归,之后如果有进行操作2的条件就使用操作2。

7.注意,在递归前后修改n1和n2的值。

#正确代码如下

#include<iostream>

using namespace std;
typedef long long LL;

char c[20];
LL ans;
int n1,n2;  //f1,f2分别为剩余次数 

void dfs(int i,LL sum){
	int x = c[i] - '0';
	if(c[i]){
		int t = min(n1,9-x);
		n1 -= t;
		dfs(i+1,sum*10+x+t);
		n1 += t;
		if(n2>x){
			n2 -= x+1;
			dfs(i+1,sum*10+9);
			n2 += x+1;
		}
	}
	else{
		ans = max(ans,sum);
	}
}

int main(){
	cin>>c>>n1>>n2;
	dfs(0,0) ;
	cout<<ans;
	return 0;
}

(感谢大佬的博客第十三届蓝桥杯C++B组国赛D题——最大数字(AC)_蓝桥杯最大数字-CSDN博客

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值