原文链接:http://kakazai.cn/index.php/Kaka/Pat/query/id/193
题目
题目链接:https://pintia.cn/problem-sets/994805342720868352/problems/994805364711604224
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 n[i]
(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 122+42+22+22+1^2, or 112+62+22+22+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 ibL.
If there is no solution, simple output Impossible
.
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 Output2:
Impossible
题意分析
- 题意
给出n,因子项数k,次方数p。将n分解为k个因子的p次方和。并且要找到因子和最大的方案,若因子和相同,则要找到子序列最大的方案,比如[12, 2, 1]比[11,3,1]更大。
- 分析
因为n最大值不超过400,因此其可选择的因子是有限的。可以求出所有可选择因子,用深度遍历DFS,逐一遍历所有可能的方案。
知识点与坑点
- 知识点
1)DFS、最大子序列
- 坑点
1)一个因子可以被选择多次
一、DFS
算法思路
1 找出所有p次方不大于n的整数,形成序列[m, m-1, m-2,…, 2, 1], m为最大值,该序列包含所有可选做因子的整数。
2 用DFS从m开始,不断往下或重复选择,直到找到满足条件的分解方案。
3 若有多个符合条件的分解方案,选择因子和最大的方案;若方案因子和相同,因为已经从最大因子开始选起,现有方案必然是序列值更大的方案,不必更新。
代码-c++版
#include<cstdio>
#include<iostream>
#include<vector>
using namespace std;
const int maxn = 401; //最多有400个因子
int num[maxn];//存储i的p次方
int n,k, p;
int maxsum = 0; //已被选择的因子总和的最大值
vector<int> temp,path; //存储符合条件的因子序列
/* 计算n的p次方*/
int power(int n, int p) {
int sum = 1;
for (int i = 0; i < p; i++) {
sum *= n;
}
return sum;
}
/* 找出p次方不超过n的所有数,并返回其最大值*/
int fun(int n, int p) {
int i;
for (i = 1; i <= n; i++) {
int temp = power(i, p);
if (temp > n)return i - 1;
num[i] = temp;
}
return i - 1;
}
/* DFS:从可能的最大因子开始遍历,直到找到符合条件的分解方案*/
void DFS(int cur, int c,int sum,int facsum) {
//cur为待选择因子;c为已被选择因子数;sum为已被选择因子的p次方总和;
//facsum为已被选择因子的和
/* 剪枝 */
//或和已经超过n;或累计因子数已经超过k;或当前因子已经为0;此时不再选择,结束
if (sum > n || c > k || cur < 1)return;
//符合条件:累加和为n,且累加因子数为k;可以结束。
if (sum == n && c == k) {
if (facsum > maxsum) { //已被选择的因子和更大,则更新
maxsum = facsum;
path = temp;
}
return;
}
//选择当前因子,或重复选择当前因子,或不选择当前因子而选择下一个因子
temp.push_back(cur); //选择当前因子cur
DFS(cur, c + 1, sum + num[cur], facsum + cur); //继续检查当前因子cur是否可再选择
temp.pop_back();//分支结束后,弹出该因子cur
DFS(cur - 1, c, sum, facsum);//不选择cur,检查cur-1是否可选择
}
int main() {
scanf("%d %d %d", &n, &k, &p);
int fac_max = fun(n, p); //最大的可能因子fac_max
/* 从最大的可能因子开始尝试,用DFS遍历各种分解方案 */
DFS(fac_max, 0, 0, 0);
/* 输出 */
if (maxsum == 0){ //没有符合条件的分解方案
printf("Impossible\n");
}
else { //有符合条件的分解方案
printf("%d = %d^%d", n, path[0], p);
for (int i = 1; i < path.size(); i++) {
printf(" + %d^%d", path[i], p);
}
}
return 0;
}
代码-python版