1103. Integer Factorization (30)

时间限制
1200 ms
内存限制
65536 kB
代码长度限制
16000 B
判题程序
Standard
作者
CHEN, Yue

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:

  1. 169 5 2

Sample Output 1:

  1. 169 = 6^2 + 6^2 + 6^2 + 6^2 + 5^2

Sample Input 2:

  1. 169 167 3

Sample Output 2:

  1. Impossible
    这是一道很考验dfs能力的题目。思路很简单,找到所有的数i(i^p<n) 然后对这个数集进行dfs
    我们来先看第一种写法
  1. void dfs(int index,int sum,int num,int factsum)
  2. {
  3.  
  4. if(sum==n&&num==k)
  5. {
  6.  
  7. if(factsum>maxsum)
  8. {
  9. maxsum=factsum;
  10. ans=temp;
  11. }
  12. else if(factsum==maxsum)
  13. {
  14.  
  15. for(int i=;i<temp.size();i++)
  16. {
  17. if(temp[i]>ans[i])
  18. {
  19. ans=temp;
  20. break;
  21. }
  22. else if(temp[i]<ans[i])
  23. break;
  24. }
  25. }
  26. return;
  27. }
  28. if(num>k||sum>n)
  29. return;
  30.  
  31. for(int i=index;i<=t;i++)
  32. {
  33. temp.push_back(v[i]);
  34.  
  35. dfs(index+,sum+w[i],num+,factsum+v[i]); //每次允许重复的数字一定比第一个数字大,并且可以重复的次数与重复的数字有关。
  36. temp.pop_back();
  37.  
  38. }*/
  39. return;
  40. }

过了一部分样例,但是仔细分析发现这种方式重复的数字是有限制的,第一个数只能重复两次,后面的数如果想要重复必须比第一个数字大,并且重复的次数也有要求。

例如对样例18 4 2就无法得到1 2 2 3因为比1大的数2最多只能重复(2-index)次,这里index为2

再看下一种写法:

  1. void dfs(int sum,int num,int factsum)
  2. {
  3. if(sum==n&&num==k)
  4. {
  5. if(factsum>maxsum)
  6. {
  7. maxsum=factsum;
  8. ans=temp;
  9. }
  10. else if(factsum==maxsum)
  11. {
  12.  
  13. for(int i=;i<temp.size();i++)
  14. {
  15. if(temp[i]>ans[i])
  16. {
  17. ans=temp;
  18. break;
  19. }
  20. else if(temp[i]<ans[i])
  21. break;
  22. }
  23. }
  24. return;
  25. }
  26. if(num>k||sum>n)
  27. return;
  28. for(int i=;i<=t;i++)
  29. {
  30. temp.push_back(v[i]);
  31.  
  32. dfs(sum+w[i],num+,factsum+v[i]); //每次允许重复的数字一定比第一个数字大,并且可以重复的次数与重复的数字有关。
  33. temp.pop_back();
  34.  
  35. }
  36. return;
  37. }

这种方法固然可行,但是肯定会超时。每次都重1开始计算,会出现大量重复的情况

  1. void dfs(int index,int sum,int num,int factsum)
  2. {
  3. if(sum==n&&num==k)
  4. {
  5. if(factsum>maxsum)
  6. {
  7. maxsum=factsum;
  8. ans=temp;
  9. }
  10. else if(factsum==maxsum)
  11. {
  12.  
  13. for(int i=;i<temp.size();i++)
  14. {
  15. if(temp[i]>ans[i])
  16. {
  17. ans=temp;
  18. break;
  19. }
  20. else if(temp[i]<ans[i])
  21. break;
  22. }
  23. }
  24. return;
  25. }
  26. if(num>k||sum>n)
  27. return;
  28. if(index>=)
  29. {
  30. temp.push_back(index);
  31. dfs(index,sum+w[index],num+,factsum+v[index]);
  32. temp.pop_back();
  33. dfs(index-,sum,num,factsum);
  34. }
  35. /*for(int i=index;i>=1;i--)
  36. {
  37. temp.push_back(v[i]);
  38.  
  39. dfs(index-1,sum+w[i],num+1,factsum+v[i]); //每次允许重复的数字一定比第一个数字大,并且可以重复的次数与重复的数字有关。
  40. temp.pop_back();
  41.  
  42. }*/
  43. return;
  44. }

正解如上。从后往前递推,每个数字都可以重复多次,如果不符合条件就减1。同时这样相等时,第一个序列即为题目要求的输出。从前往后仍然可能会超时,因为初始的数字过于小了。

网上题解:

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

我们利用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中并且向后枚举,即

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

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

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

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

这个题解是典型的剪枝方法

  1. #include <iostream>
  2. #include <cstdio>
  3. #include <cmath>
  4. #include <vector>
  5. #include <algorithm>
  6.  
  7. using namespace std;
  8.  
  9. typedef long long lint;
  10.  
  11. lint N,K;
  12. int P;
  13.  
  14. lint lpower(lint n, lint p){
  15. if(n == ) return ;
  16. int factor = n;
  17. for(int i = ; i < p; i++) n *= factor;
  18. return n;
  19. }
  20.  
  21. vector<int> finalFactor;
  22. int nowSum = ;
  23.  
  24. bool dfs(lint N, int cur, vector<int>& factors){
  25. if(cur == K){
  26. if(N == ){
  27. int sum = ;
  28. for(int i = ; i < factors.size(); i++){
  29. sum += factors[i];
  30. }
  31. if(sum >= nowSum){
  32. finalFactor = factors;
  33. nowSum = sum;
  34. }
  35. return true;
  36. }else return false;
  37. }
  38. lint upper = sqrt((double)N);
  39. lint lower = cur > ? factors[cur - ] : ;
  40. for(lint i = lower; i <= upper; i++){
  41. lint res = lpower(i,P);
  42. if(N >= res){
  43. factors[cur] = i;
  44. dfs(N-res,cur+,factors);
  45. }else{
  46. return false;
  47. }
  48. }
  49. return true;
  50. }
  51.  
  52. int main()
  53. {
  54. cin >> N >> K >> P;
  55. vector<int> factors(K);
  56. dfs(N,,factors);
  57. reverse(finalFactor.begin(),finalFactor.end());
  58. if(finalFactor.size() == K){
  59. printf("%d = ",N);
  60. printf("%d^%d",finalFactor[],P);
  61. for(int i = ; i < finalFactor.size(); i++){
  62. printf(" + %d^%d",finalFactor[i],P);
  63. }
  64. }else{
  65. cout << "Impossible";
  66. }
  67. cout << endl;
  68.  
  69. return ;
  70. }

PAT1103的更多相关文章

随机推荐

  1. Dom对象和jQuery对象的相互转化

    01.jQuery对象 1.jQuery对象就是通过对jQuery包装dom对象后产生的对象. 2.虽然jQuery对象是包装DOM对象后产生的,但是jQuery无法使用DOM对象的任何方法,同理DO ...

  2. leetcode988

    public class Solution { private Stack<string> ST = new Stack<string>(); private string S ...

  3. Appium -选择、操作元素4

    webvie的测试 混合(Hybrid)应用 一部分是原生界面和代码,而一部分是内嵌网页 比如微信.支付宝 内嵌了一个浏览器内核,由浏览器内核实现的 安卓应用中的内嵌的展示网页内容的模块,我们称之为w ...

  4. centos下查看python的安装目录

    直接用python命令,打印sys的path即可: >>> import sys >>> print(sys.path) ['', '/usr/local/lib/ ...

  5. H5自动准备杂记

    由于之前没做过UI自动化,近期准备做H5自动化,要学的东西还是很多. 1.本地debug环境:android studio + android SDK(想要调试通要关注:驱动.手机开发者模式要打开) ...

  6. (转载)Android下Affinities和Task

    源文链接:http://appmem.com/archives/405 1.Activity和Task task就好像是能包含很多activity的栈. 默认情况下,一个activity启动另外一个a ...

  7. Oracle问题小结

    1.win8.1安装Oracle11g后,重启电脑,出现黑屏. 解决办法:安全模式下,找到以oracle开头的全部服务,所有“自动”或者“自动(延迟启动)”的都设置为“手动”,只需要开启OracleO ...

  8. Unable to connect to zookeeper server within timeout: 5000

    错误 严重: StandardWrapper.Throwable org.springframework.beans.factory.BeanCreationException: Error crea ...

  9. linux 再多的running也挡不住锁

    再续<linux 3.10 一次softlock排查>,看运行态进程数量之多: crash> mach MACHINE TYPE: x86_64 MEMORY SIZE: GB CP ...

  10. 1005 继续(3n+1)猜想 (25 分)

    1005 继续(3n+1)猜想 (25)(25 分) - 过期汽水的博客 - CSDN博客https://blog.csdn.net/qq_40167974/article/details/80739 ...