0
点赞
收藏
分享

微信扫一扫

【1103】Integer Factorization (DFS)

瑾谋 2022-07-14 阅读 37


1.题目

​​https://pintia.cn/problem-sets/994805342720868352/problems/994805364711604224​​​ 给出正整数N,K,P,求N由K个整数的分别的P次方的和的情况,如果有多种情况则选择底数和最大的方案。
举例:169 5 2
输出:159=6^ 2 + 6^ 2+6^ 2+6^ 2+5^ 2

2.思路

(1)开一个vector数组fac存0^ p ,1^ p… i ^ p.

(2)DFS:
分叉口:利用DFS对​​fac[index]​​​进行选择,有“选”与“不选”两种选择,如果不选,则把问题转化为对fac[index]进行选择;如果选择,由于每个数字可以重复选择即下一次还能选择fac[index]。
递归边界:2个return,第一个满足​​sum == N且nowK==k​​​成立时则找到一个满足条件的序列——记住为了找出多方案的最优情况,需要判断底数之和facSum是否比一个全局记录的最大底数之和maxFacSum更大,更大则更新。
第二个return是底数之和大于N或底数个数大于K就不阔能出答案了,马上return。

(3)为了让结果能够保证字典序大的序列优先被选中,让index从大到小递减来遍历,这样总是能先选中fac中较大的数。

3.代码

#include<cstdio>
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
const int maxn=30;
vector<int>fac,ans,temp;//fac记录i^p
int n,k,p,maxFacSum=-1;
int pinfang(int x){
int ans=1;
for(int i=0;i<p;i++){
ans*=x;
}
return ans;
}
//init函数预处理fac数组,注意把0也存进去
void init(){
int i=0,temp1=0;
while(temp1<=n){
fac.push_back(temp1);
temp1=pinfang(++i);
}
}
void DFS(int index,int nowK,int sum,int facSum){
if(sum==n&&nowK==k){//找到一个满足的序列
if(facSum>maxFacSum){
ans=temp;
maxFacSum=facSum;//更新最大底数之和
}
return;
}
if(sum>n||nowK>k)
return;//不会产生答案,直接返回
if(index-1>=0){//fac[0]不需要选择,从大到小
temp.push_back(index);
DFS(index,nowK+1,sum+fac[index],facSum+index);
temp.pop_back();
DFS(index-1,nowK,sum,facSum);
}
}
int main(){
scanf("%d%d%d",&n,&k,&p);
init();
DFS(fac.size()-1,0,0,0);//从fac的最后一位开始往前搜索
if(maxFacSum==-1)
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);
}
system("pause");
}

4.注意

(1)多方案时判断是否更优的做法的时间复杂度最好是O(1),否则容易超时。因此必须在DFS的参数中记录当前底数之和facSum,避免在找到一组解时计算序列的底数之和。
(2)和(1)一样,不要在找到一组解时才判断vector型的temp和ans数组的字典序,而应该让index从大到小进行选择,这样fac[index]大的就会相对早地被选中。


举报

相关推荐

0 条评论