此题解法参考《算法笔记》
题意解读:
输入N,K,P,要求找到K个数(可以相同)的P次方的和等于N,若能找到按要求输出,找不到则输出“Impossible”。
分析:
因为要求的都是数的P次方,不妨先将不大于N的数的P次方先按序求出来,用一个vector存放,然后再进行DFS,从大到小找(因为题目中要求从大到小输出且多种情况时找所有数字加起来和最大的那个,所以从大到小找可以很方便的解决这个问题),同时定义变量maxFacSum来记录下当前找到的符合要求的序列的数字和。
因为这里不清楚数据的具体规模,使用容器vector会方便些,但使用数组应该也是可以的,只要开大些就可以了;另一个原因是使用容器的话,再给最终序列ans赋值时会方便些,直接ans=temp就可以了。
有关DFS的过程,我也看过一些相关方面的资料,但是自己对DFS这种常用递归实现的逻辑还是时常不能理解的,但它其实就是一个模板(如下)。先确定结束的条件(包括满足条件了返回和不满足条件出界了返回),然后就是从头到尾的遍历,对于每一次遍历都进行DFS尝试。有关具体的内在解释我也不是很理解,如果有大佬能讲清楚还望不吝赐教。同学给我举了个例子,我觉得还是挺易懂的。
模板:
void dfs(int step)
{
判断边界
尝试每一种可能 for(i=1;i<=n;i++)
{
继续下一步 dfs(step+1);
}
return
}
例子:求n!
int fac(int i){
//到边界了则返回
if(i==1) return 1;
//否则就一直进行下去
else return i*fac(i-1);
}
参考代码:
using namespace std;
#include<bits/stdc++.h>
int n,k,p;
vector<int> fac;
vector<int> ans;
vector<int> temp;
int maxFacSum=0;
void DFS(int index,int nowK,int sum,int facSum){
if(sum>n || nowK>k) return ;
if(sum == n && nowK == k)
{
if(facSum>maxFacSum)
{
maxFacSum=facSum;
ans=temp;
}
return;
}
if(index>=1)
{
temp.push_back(index);
DFS(index,nowK+1,sum+fac[index],facSum+index);
temp.pop_back();
DFS(index-1,nowK,sum,facSum);
}
return ;
}
int f(int i){
int sum=1;
for(int j=0;j<p;j++)
{
sum*=i;
}
return sum;
}
int main(){
scanf("%d %d %d",&n,&k,&p);
int num=0,tmp=0;
while(tmp<=n)
{
fac.push_back(tmp);
tmp=f(++num);
}
DFS(fac.size()-1,0,0,0);
if(maxFacSum == 0) printf("Impossible\n");
else
{
printf("%d = %d^%d",n,ans[0],p);
for(int i=1;i<ans.size();i++)
{
printf(" + %d^%d",ans[i],p);
}
}
return 0;
}