题目链接
题目分析
题意:分解因式 – K个数 的 P次方之和 = N
数值范围: N <= 400, K <= N, 1 < P <= 7
多方案时选择基数和最大的,基数和也相同时按字典序选择最靠前的
解题思路
1、由于P
确定,可以提前确定P
次幂小于N
的数,用数组fac[]
保存起来
2、每次DFS()
确定是否加 fac[i]
,形成两个分支
3、需要传的参数有:
cur
: 从N递减遍历求幂次和,保证字典序
tempK
: 当前已加的个数(<=K)
tempN
: 当前的和
tempS
: 当前已入选的底数的和
4、剪枝策略:
①、num > K
【入选的数超额】
②、tempN > N
【幂次和溢出】
③、cur <= 0
【所有数遍历完成】
④、cur
的P
次幂已>N
AC程序(C++)
/**************************
//@Author: 3stone
//@ACM: PAT-A1103
//@Time: 18/2/2
//@IDE: VS2017
***************************/
#include<cstdio>
#include<iostream>
#include<vector>
#define maxSize 1000
using namespace std;
int N, K, P, maxSum = 0;
int fac[maxSize]; //保存 key^P ,避免重复计算
vector<int> ans, temp; //存储已选择的底数
//计算幂次值
int getK_P(int value) {
int t = P - 1, temp0 = value;
while (t > 0) {
value = temp0 * value;
t--;
}
return value;
}
void init() { //初始化fac[]
int value;
for (int i = 1; i <= N; i++) {
value = getK_P(i);
if (value > N) break;
fac[i] = value;
}
}
//cur:当前递减到的数值
void DFS(int cur, int tempK, int tempN, int tempS) {
if (tempK > K || cur <= 0 || tempN > N) return; //剪枝
if (K == tempK && tempN == N) { //满足题意
if (tempS > maxSum) {//取最优项,判底数和是否最大
ans = temp;
maxSum = tempS;
}
}
else {
if (fac[cur] != 0) { //此数的P次幂小于N,即可加(剪枝)
temp.push_back(cur);
DFS(cur, tempK + 1, tempN + fac[cur], tempS + cur);//加入此数
temp.pop_back();
}
DFS(cur - 1, tempK, tempN, tempS);// 不加此数
}
}
int main() {
int tempN = 0, tempK = 0, tempS = 0;// 幂次和, 已选个数,数值和
while (scanf("%d %d %d", &N, &K, &P) != EOF) {
memset(fac, 0, sizeof(fac));
init();
temp.clear(); //清空
ans.clear();
// 当前数,当前幂次和,已选个数,底数和
DFS(N, tempN, tempK, tempS);
if (ans.size() != 0) { //输出
printf("%d = ", N);
vector<int>::iterator flag = ans.end();
for (vector<int>::iterator it = ans.begin(); it != flag - 1; it++) {
printf("%d^%d + ", *it, P);
}
printf("%d^%d\n", *(flag - 1), P);
}
else {
printf("Impossible\n");
}
}
system("pause");
return 0;
}