您的位置:首页 > 其它

1103. Integer Factorization (30)

2015-09-15 13:09 459 查看
题目如下:

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 = n1^P + ... nK^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 122 + 42 + 22 + 22 +
12, or 112 + 62 + 22 + 22 + 22, 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<L and aL>bL

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 Output 2:
Impossible


本题考察了DFS的回溯剪枝。

为了顺应题目找到最大系数和或者最大系数列,我们从小到大进行枚举,这样即使碰到了和相等的情况,由于是递增着枚举的,因此直接覆盖原来的系数列,得到的就是最终满足条件的系数列。

我们利用DFS来从小到大的枚举,DFS函数的参数如下:

dfs(long long N, int cur, vector<int>& factors);

①其中N是当前值,从最初的输入开始,逐步减去每个系数的运算结果;cur是枚举到的位置,从0开始,依次填入factors容器中,当cur==K时,枚举已经结束,我们判断N是否为0,为0则找到了一个满足条件的系数列,并且这个系数列按照升序存储在factors中。注意到cur==K但N≠0是我们的第一个剪枝条件。

②为了保证枚举从小到大开始,在每次枚举开始前计算lower和upper两个值,其中lower由factors中刚刚枚举完的上一个值确定,如果当前是枚举的起始点,则从1开始;upper为根号下N,因为系数的次方P>1,因此最大的系数不可能超过根号N。

③对lower到upper内的每一个值,计算系数的P次方,用res表示。如果N≥res,则说明合法,将其填入factors中并且向后枚举,即

factors[cur] = i;
dfs(N-res,cur+1,factors);


如果N<res,说明系数偏大,又因为系数是递增枚举的,所以此后都不满足,直接返回,这是我们的第二个剪枝条件。

综合上面两个剪枝条件,即可写出高效的dfs算法来枚举结果,为了能得到满足题目要求的系数列,我们设置全局变量nowSum和finalFactor,每次找到一个系数列,就求其系数和sum,如果sum≥nowSum,则更新nowSum与finalFactor,等号涵盖了题目中的第二个条件,因为后面出现的系数列一定大于前面出现的系数列(递增枚举)。

最后如果finalFactor规模为K,则说明找到,先反转,后输出,注意格式;否则输出Impossible。

代码如下:

#include <iostream>
#include <cstdio>
#include <cmath>
#include <vector>
#include <algorithm>

using namespace std;

typedef long long lint;

lint N,K;
int P;

lint lpower(lint n, lint p){
if(n == 1) return 1;
int factor = n;
for(int i = 1; i < p; i++) n *= factor;
return n;
}

vector<int> finalFactor;
int nowSum = 0;

bool dfs(lint N, int cur, vector<int>& factors){
if(cur == K){
if(N == 0){
int sum = 0;
for(int i = 0; i < factors.size(); i++){
sum += factors[i];
}
if(sum >= nowSum){
finalFactor = factors;
nowSum = sum;
}
return true;
}else return false;
}
lint upper = sqrt((double)N);
lint lower = cur > 0 ? factors[cur - 1] : 1;
for(lint i = lower; i <= upper; i++){
lint res = lpower(i,P);
if(N >= res){
factors[cur] = i; dfs(N-res,cur+1,factors);
}else{
return false;
}
}
return true;
}

int main()
{
cin >> N >> K >> P;
vector<int> factors(K);
dfs(N,0,factors);
reverse(finalFactor.begin(),finalFactor.end());
if(finalFactor.size() == K){
printf("%d = ",N);
printf("%d^%d",finalFactor[0],P);
for(int i = 1; i < finalFactor.size(); i++){
printf(" + %d^%d",finalFactor[i],P);
}
}else{
cout << "Impossible";
}
cout << endl;

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: