[PAT] A1103 Integer Factorization

(dfs深度优先搜索)

思路

先把i从0开始所有的i的p次方的值存储在v[i]中,直到v[i] > n为止。(如果在递归过程中计算次方,会做很多重复工作,很浪费时间。)
然后深度优先搜索,记录当前正在相加的index(即v[i]的i的值),当前的总和tempSum,当前K的总个数tempK,以及因为题目中要求输出因子的和最大的那个,所以保存一个facSum为当前因子的和,让它和maxFacSum比较,如果比maxFacSum大就更新maxFacSum和要求的ans数组的值。
在ans数组里面存储因子的序列,tempAns为当前深度优先遍历而来的序列,从v[i]的最后一个index开始一直到index == 1,因为这样才能保证ans和tempAns数组里面保存的是从大到小的因子的顺序。
一开始maxFacSum == -1,如果dfs后maxFacSum并没有被更新,还是-1,那么就输出Impossible,否则输出答案。
剪枝:
1.tempK==K但是tempSum!=n的时候需要剪枝
2.在枚举的时候,按顺序枚举,上界或者下界可进行剪枝
3.当且仅当tempSum + v[index] <= n时,进行下一层的DFS,而不要进入下一层DFS发现不满足条件再返回,这样开销会比较大
4.每次temv的push_back、pop_back都需要重新分配内存空间,比较耗时,由于答案的序列长度是确定的,可以将ans序列初始化为定长的,这样在递归的过程中就不需要push、pop; pow的计算结果可以保存下来,以免重复计算,耗用多余的时间

1.要先存好次方计算后的值,避免递归时重复计算。
2.直接利用maxsum来判断是否有解,通过设初值为负数。无需额外建立标记判断。
3.倒着递归,从大数开始判断。

AC代码

/*第二次写*/
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<math.h>
#include<vector>
using namespace std;
int n, k, p, maxsum = -1;
vector<int>num, ans, bestans;
void DFS(int index, int result, int sum, int x) {
	if (result == n && x == k) {
		if (sum > maxsum) {
			bestans = ans;
			maxsum = sum;
		}
		else if (sum == maxsum) {
			int i = k - 1;
			while (i >= 0 && ans[i] == bestans[i])i--;
			if (ans[i] > bestans[i])bestans = ans;
		}
		return;
	}
	else if (index < 0 || x >= k || result >= n)return;
	if (result + num[index] <= n) {
		ans[x] = index + 1;
		DFS(index, result + num[index], sum + index, x + 1);
	}
	DFS(index - 1, result, sum, x);
}

int main() {
	int i, a, b;
	scanf("%d%d%d", &n, &k, &p);
	ans.resize(k); bestans.resize(k);
	for (i = 1; i <= n; i++) {
		a = pow(i, p);	
		if (a > n)break;
		num.push_back(a);
	}
	DFS(num.size() - 1, 0, 0, 0);
	if (maxsum < 0)printf("Impossible");
	else {
		printf("%d = %d^%d", n, bestans[0], p);
		for (i = 1; i < k; i++)printf(" + %d^%d", bestans[i], p);
	}
	return 0;
}
#define _CRT_SECURE_NO_WARNINGS
#include<cstdio>
#include<iostream>
#include<vector>
#include<algorithm>
#include<cmath>
using namespace std;
#define MAX 500
int n, k, p, maxsum = -1;
vector<int>v;
vector<int>solution, maxsolution;
void optmax() {
	int i = 0;
	while (solution[i] == maxsolution[i])i++;
	if (solution[i] > maxsolution[i])
		maxsolution = solution;
}
void DFS(int index, int count, int ans, int sum) {
	if (count == k && ans == n) {
		if (maxsum < sum) {
			maxsum = sum;
			maxsolution = solution;
		}
		else if (maxsum == sum) optmax();  //此处可以不用判断相等情况,也能AC。
		return;
	}
	if (index == 0 || ans > n || count >= k)return;
	if (ans + v[index] <= n) {
		solution.push_back(index);
		DFS(index, count + 1, ans + v[index], sum + index);
		solution.pop_back();
	}
	DFS(index - 1, count, ans, sum);
}
int main() {
	scanf("%d%d%d", &n, &k, &p);
	int temp = 0, index = 1;
	while (temp <= n) {
		v.push_back(temp);
		temp = pow(index, p);
		index++;
	}
	DFS(v.size() - 1, 0, 0, 0);
	if (maxsum < 0)printf("Impossible");
	else {
		printf("%d = %d^%d", n, maxsolution[0], p);
		for (int i = 1; i < k; i++)
			printf(" + %d^%d", maxsolution[i], p);
	}
	return 0;
}

如果改成正着来,测试点5就超时了...实在想不通是什么回事,希望走过路过的大神们帮我看看,感激不尽!!!
(我想应该是从大数开始比较容易到达边界,减少了递归次数)

#define _CRT_SECURE_NO_WARNINGS
#include<cstdio>
#include<iostream>
#include<vector>
#include<map>
#include<algorithm>
#include<cmath>
using namespace std;
#define MAX 500
int n, k, p, maxsum = -1;
vector<int>v;
vector<int>solution, maxsolution;
bool cmp(int a, int b) { return a > b; }
void optmax() {
	int i = 0;
	while (solution[i] == maxsolution[i])i++;
	if (solution[i] > maxsolution[i])
		maxsolution = solution;
}
void DFS(int index, int count, int ans, int sum) {
	if (count == k && ans == n) {
		if (maxsum < sum) {
			maxsum = sum;
			maxsolution = solution;
		}
		else if (maxsum == sum) optmax();
		return;
	}
	if (index >= v.size() || ans > n || count >= k)return;
	if (ans + index <= n) {
		solution[count] = index;
		DFS(index, count + 1, ans + v[index], sum + index);
	}
	DFS(index + 1, count, ans, sum);
}
int main() {
	scanf("%d%d%d", &n, &k, &p);
	solution.resize(k);
	int temp = 0, index = 1;
	while (temp <= n) {
		v.push_back(temp);
		temp = pow(index, p);
		index++;
	}
	DFS(1, 0, 0, 0);
	if (maxsum < 0)printf("Impossible");
	else {
		printf("%d = %d^%d", n, maxsolution[k - 1], p);
		for (int i = k - 2; i >= 0; i--)
			printf(" + %d^%d", maxsolution[i], p);
	}
	return 0;
}
原文地址:https://www.cnblogs.com/yue36/p/13346039.html