【PAT甲级】1103 Integer Factorization (30分)

解题过程的小记录,如有错误欢迎指出。

难度:五星(DFS选择满足条件的最优序列)

题目分析

找出k个数的p次方之和为n

注意点

  1. 最终要找的数列是满足一系列条件的的底数,次方和知识中间寻找所需要的条件
  2. 最好在开始的init中就找出所有的<=n的次方数,简化后续的运算
  3. 底数从大到小开始找,这样就省去了在出现tie的时候比较的情况,因为从大到小找的时候,先找出的满足的序列,一定是各个数更大的
  4. 在进行下一层搜索之前,先看所加在一起的和是否超过了n,如果超过了就没有必要进入到下一层,因为进入到下一层再判断的话,会更加费时

我的解题过程

思路

  1. 初始化数组Fac,用于保存<=n的底数为下标的p次方的数
  2. 设置temp数组保存过程中所用到的底数,ans数组保存满足题目条件的底数(也就是答案)
  3. 写DFS函数(看代码理解吧)

bug

  1. 自己写的时候没有init而且还是从小往大找,各种超时报错,死得很惨烈
  2. maxFacSum初始化值要设为-1,不然好像有一个测试点会报错,不过这种不参加运算(参加运算的是tempFacSum),只用比较然后直接赋值的都可以初始化为-1,方便后续的比较

代码

#include<iostream>
#include<vector>
#include<math.h>

using namespace std;

vector<int> temp, ans, fac;//temp用来存储中间结果,ans用来返回最终结果,fac用来存储x的p次方的数
int n, k, p, maxFacSum = -1;

void init() {//把<=n的p次方的数都存储到fac中,对应的下标是底数
	int temp = 0, index = 1;
	while (temp <= n) {
		fac.push_back(temp);
		temp = pow(index, p);
		index++;
	}
}

void DFS(int index, int tempSum, int tempK, int facSum) {
	if (tempK == k) {//当前的底数个数为所要求的k时
		if (tempSum == n&&facSum > maxFacSum) {//当前的底数的p次方和为n,且底数和大于原先记录的最大和
			ans = temp;		//进行更新
			maxFacSum = facSum;
		}
		return;
	}
	if (tempSum > n) return;//剪枝  当当前的底数和>n时 不再继续搜索
	if (index >= 1) {//index为0的时候记录的是0的p次方=0不需要考虑
		if (tempSum + fac[index] <= n) {//选入index
			temp.push_back(index);//压入过程底数数组
			DFS(index, tempSum + fac[index], tempK + 1, facSum + index);
			temp.pop_back();//结束搜寻后退出数组
		}
		DFS(index - 1, tempSum, tempK, facSum);//不选入index
		//if (index == 1) return;
		//index--;//这个是柳神方法中的while所用到的
	}
}


int main()
{
	scanf("%d%d%d", &n, &k, &p);//要求k个数的p次方之和为n
	init();
	DFS(fac.size() - 1, 0, 0, 0);
	if (ans.size() != 0) {
		printf("%d =", n);
		for (int i = 0; i < k; i++) {
			printf(" %d^%d", ans[i], p);
			if (i != k - 1) printf(" +");
		}
	}
	else {
		printf("Impossible");
	}
    return 0;
}

dalao的代码

全部代码因版权原因不放出来,大家可以自行去柳神博客购买或者参考晴神的上机笔记~

借鉴点

本篇看两位大佬的代码的话,只要看DFS部分即可,其它部分看自己

  1. 柳神的代码在DFS部分采用了while直到index不满足条件,这种方法会用时更少
  2. 晴神的代码在DFS部分采用了写两个DFS分别进行选和不选的递归,用时更多,但更易于理解
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值