有技巧地枚举所有选数的可能,形成二叉树,再通过递归实现深度优先遍历,每次到达叶子节点就进行一次结果比较,确定是否更新最终结果。算法笔记上写的很好,一个数只能选一次的情况,与一个数可以选多次,稍微更改即可。备选数的最大值为P次根号下N,从最大值开始选会更快。另外就是预处理的技巧,遍历时涉及到重复计算一个数的P次方,提前用一个数组保存下来,可以节省时间。
#include <cstdio>
#include <vector>
#include <cmath>
using namespace std;
int N, K, P, ans_sum=0;
vector<int> ans, temp;
bool better_check();
//已选好ct个数,下一个备选数为num
void proc(int num, int ct, int sum_p, int temp_sum, double pow_p[]);
int main(){
scanf("%d%d%d", &N, &K, &P);
int roof=1;
while(pow(roof, P)<N){
roof++;
}
double pow_p[roof+1];
for(int i=1; i<=roof; i++){
pow_p[i] = pow(i, P);
}
proc(roof, 0, 0, 0, pow_p);
if(ans.empty()) printf("Impossible");
else{
printf("%d =", N);
for(int i=0; i<K; i++){
printf(" %d^%d", ans[i], P);
if(i<K-1) printf(" +");
}
}
return 0;
}
bool better_check(){
for(int i=0; i<K; i++){
if(ans[i]!=temp[i]) return ans[i]<temp[i];
}
}
void proc(int num, int ct, int sum_p, int temp_sum, double pow_p[]){
if(ct==K && sum_p==N){
if(temp_sum>ans_sum){
ans_sum = temp_sum;
ans = temp;
return;
}
else if(temp_sum==ans_sum && better_check()){
ans_sum = temp_sum;
ans = temp;
return;
}
return;
}
if(num<1 || ct==K || sum_p>N) return;
temp.push_back(num);
proc(num, ct+1, sum_p+pow_p[num], temp_sum+num, pow_p);
temp.pop_back();
proc(num-1, ct, sum_p, temp_sum, pow_p);
}