PAT Advanced 1103 Integer Factorization (30) [深度优先搜索DFS]
题目
The K-P factorization of a positive integer N is to write N as the sum of the P-th power of K positive integers. You are supposed to write a program to find the K-P factorization of N for any positive integers N, K and P.
Input Specification:
Each input file contains one test case which gives in a line the three positive integers N (<=400), K (<=N) and P (1<P<=7). The numbers in a line are separated by a space.
Output Specification:
For each case, if the solution exists, output in the format:
N = n[1]^P + … n[K]^P
where ni (i=1, … K) is the i-th factor. All the factors must be printed in non-increasing order. Note: the solution may not be unique. For example, the 5-2 factorization of 169 has 9 solutions, such as 12^2 + 4^2 + 2^2 + 2^2 + 1^2, or 11^2 + 6^2 + 2^2 + 2^2 + 2^2, or more. You must output the one with the maximum sum of the factors. If there is a tie, the largest factor sequence must be chosen — sequence { a1, a2, … aK} is said to be larger than { b1, b2, … bK } if there exists 1<=L<=K such that ai=bi for i
Sample Input 1:
169 5 2
Sample Output 1:
169 = 6^2 + 6^2 + 6^2 + 6^2 + 5^2
Sample Input 2:
169 167 3
Sample Output 2:
Impossible
题目分析
已知N,求k个p次幂的数之和=N
若有多个序列,取底数和最大的序列;若仍有多个序列,取大序列(两个序列,前i项都相等,第i+1项较大者)
输出要求:序列中数字非升序排列
解题思路
- 因为p不变,可以预处理将所有p次方结果<=n的数字保存于容器(若某个数的p次方大于n,那么这个数字不可能被选中)
- dfs深度搜索,从大数字到小数字遍历,被选中数字可以重复再次被选中,所以当前数字有两种支路:当前数字被选择并记录;当前数字不被选择跳过选择下个数字
- dfs退出条件:
3.1 (无效序列)已被选中的数字之和大于n
3.2 (无效序列)已被选中的数字个数大于k
3.3 (有效序列)已被选中的数字之和等于n并且已被选中的数字个数等于k,更新最优解
Code
#include <iostream>
#include <vector>
using namespace std;
int n,k,p,maxSum;
vector<int> fac,ans,temp;
int power(int x) {
// 方法一:p个x相乘
int ans =1;
for(int i=0; i<p; i++)
ans*=x;
return ans;
//方法二:使用cmath中power函数
}
void init() {
for(int i=0; power(i)<=n; i++)
fac.push_back(power(i));
}
// index 当前访问的索引
// numK 当前已经选择的数字个数
// sum 当前已经选择的数字之和
// facnum 当前已经选中的数字底数之和
void dfs(int index, int numK,int sum,int facSum) {
if(sum==n&&numK==k) {
// 符合条件,更新最优解
if(facSum>maxSum) {
ans=temp; //保存序列
maxSum=facSum; //更新底数和最大值
}
return;
}
if(sum>n||numK>k)return;
if(index>=1) { //不选0
temp.push_back(index);
dfs(index, numK+1, sum+fac[index], facSum+index); //选择当前数字
temp.pop_back();
dfs(index-1, numK, sum, facSum); //不选择当前数字
}
}
int main(int argc,char *argv[]) {
scanf("%d %d %d",&n,&k,&p);
init(); //预处理数字的固定幂次结果
dfs(fac.size()-1,0,0,0);
if(ans.empty()) printf("Impossible");
else {
printf("%d = %d^%d",n, ans[0], p);
for(int i=1; i<k; i++)
printf(" + %d^%d", ans[i], p);
}
return 0;
}
Code 2
#include <iostream>
#include <vector>
#include <algorithm>
#include <cmath>
using namespace std;
const int maxn=410;
int n,k,p,pw[maxn],maxi,maxfacsum=-1;
vector<int> ans,temp;
void initial(int v) {
for(int i=0; pow(i,p)<=v; i++) {
pw[i]=pow(i,p);
maxi = i;
}
}
void dfs(int index,int tempsum,int tempk,int facsum) {
if(tempk==k) {
if(tempsum==n&&facsum>maxfacsum) {
maxfacsum=facsum;
ans=temp;
}
return;
}
// while(index>=1){
// if(tempsum+pw[index]<=n){
// temp[tempk]=index;
// dfs(index,tempsum+pw[index],tempk+1,facsum+index);
// }
//// if(index==1)return;
// index--;
// }
for(int i=index; i>=1; i--) {
if(tempsum+pw[i]<=n) {
temp[tempk]=i;
dfs(i,tempsum+pw[i],tempk+1,facsum+i);
}
}
}
int main(int argc,char * argv[]) {
scanf("%d%d%d",&n,&k,&p);
initial(n);
temp.resize(k);
dfs(maxi,0,0,0);
if(maxfacsum==-1) {
printf("Impossible");
return 0;
}
printf("%d =",n);
for(int i=0; i<ans.size(); i++) {
if(i!=0)printf(" +");
printf(" %d^%d",ans[i],p);
}
return 0;
}