0
点赞
收藏
分享

微信扫一扫

*PAT_甲级_1103 Integer Factorization (30point(s)) (C++)【DFS进阶用法】


目录

​​1,题目描述​​

​​题目大意​​

​​2,思路​​

​​数据结构​​

​​算法​​

​​3,AC代码​​

​​4,解题过程​​

​​第一搏​​

​​第二搏​​

​​第三搏​​

1,题目描述

*PAT_甲级_1103 Integer Factorization (30point(s)) (C++)【DFS进阶用法】_DFS进阶用法

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次方之和,要求当结果不唯一时,取因子之和最大的,仍不唯一,则将序列按照从大到小排序,选择较大序列(从第一个数往后,直到当前位置的数组A中的数大于数组B中的数;

不存在这样的分解方法时,输出Impossible;

 

2,思路

参考大神的解法:​​@日沉云起【pat甲级1103. Integer Factorization (30)】​​

(解题过程的第二搏第三搏中的思路均可通过测试,这里仅详细介绍最简解法)

数据结构

  • vector<int> tem:暂时存放结果序列;
  • vector<int> ans:结果序列;
  • vector<int> powValue:存储所有不超过N的n^P中的n;
  • DFS函数参数:start指向powValue的特定位置,dep深度(个数),facSum因子之和,powSum指数之和;

算法

  1. 对不超过N的n^P进行打表,并把结果存储到powValue中,DFS遍历时针对此表进行:
  2. *PAT_甲级_1103 Integer Factorization (30point(s)) (C++)【DFS进阶用法】_DFS进阶用法_02

  3. 出口(dep >= K || powSum >= N,若满足dep == K && powSum == N && facSum > maxFacSum则更新ans);遍历(选择当前的start;不选择当前的start,而是更小的数)注意入栈/出栈的时机,以及递归的参数;
  4. *PAT_甲级_1103 Integer Factorization (30point(s)) (C++)【DFS进阶用法】_DFS进阶用法_03

  5. 函数调用及输出:
  6. *PAT_甲级_1103 Integer Factorization (30point(s)) (C++)【DFS进阶用法】_1103_04

 

3,AC代码

(即第三搏中的代码)

#include<bits/stdc++.h>
using namespace std;
int N, K, P;//N给出的数 K因子个数 P因子的指数
vector<int> tem, ans, powValue;
int maxFacSum = 0;
void initPow(){ //下标对应因子 值对应因子的P次方
powValue.push_back(0);
while(powValue.back() < N)
powValue.push_back(pow(powValue.size(), P)); // !!!妙啊
}
void dfs(int start, int dep, int facSum, int powSum){ //start指向powValue的特定位置 dep深度 facSum因子之和 powSum指数之和
if(dep >= K || powSum >= N){
if(dep == K && powSum == N && facSum > maxFacSum){
maxFacSum = facSum;
ans = tem;
}
return;
}
if(start >= 1){
tem.push_back(start);
dfs(start, dep+1, facSum+start, powSum+powValue[start]); //powValue[start]即start的P次方
tem.pop_back();
dfs(start-1, dep, facSum, powSum); //未选择当前的start 而是选择更小的数
}
}
int main(){
#ifdef ONLINE_JUDGE
#else
freopen("1.txt", "r", stdin);
#endif // ONLINE_JUDGE

scanf("%d %d %d\n", &N, &K, &P);
initPow();
dfs(powValue.size()-1, 0, 0, 0); //从大到小开始选择
if(ans.size() == K){
printf("%d = %d^%d", N, ans[0], P);
for(int i = 1; i < ans.size(); i++)
printf(" + %d^%d", ans[i], P);
}else
printf("Impossible");
return 0;
}

 

4,解题过程

第一搏

想到了DFS,但是连样例都没运行出来。。。

#include<bits/stdc++.h>
using namespace std;
int N, K, P;//N给出的数 K因子个数 P因子的指数
vector<int> tem, ans;
bool cmp2(int a, int b) {return a > b;}
bool cmp1(vector<int>& A, vector<int>& B){
int sumA = 0, sumB = 0;
if(B.size() == 0) return true;
for(int i = 0; i < K; i++){
sumA += A[i];
sumB += B[i];
}
if(sumA != sumB) return sumA > sumB;
sort(A.begin(), A.end(), cmp2);
sort(B.begin(), B.end(), cmp2);
for(int i = 0; i < K; i++)
if(A[i] != B[i])
return A[i] > B[i];
}

void dfs(int start, int dep, int sum){
tem.push_back(start);
sum += (int)pow(start, P);
// if(sum > N){
// tem.pop_back();
// return;
// }
if(dep >= K){
//printf("YES1\n");
if(sum == N){
for(int i = 0; i < tem.size(); i++)
printf(" %d", tem[i]);
printf("\n");
if(cmp1(tem, ans))
ans = tem;
}

//printf("YES2\n");
tem.pop_back();
return;
}
for(int i = start; i <= 20; i++){//P最小为2 N最大为400 20^2=400
dfs(i, dep+1, sum);
//tem.pop_back();
}
tem.pop_back();
}
int main(){
#ifdef ONLINE_JUDGE
#else
freopen("1.txt", "r", stdin);
#endif // ONLINE_JUDGE

scanf("%d %d %d\n", &N, &K, &P);
for(int i = 1; i <= 20; i++)
dfs(i, 1, 0);
//cout<<ans.size()<<endl;
// for(int i = 0; i < ans.size(); i++)
// printf(" %d", ans[i]);
return 0;
}

看着自己写的代码,都感觉时间复杂度要炸开了。。。

 

第二搏

向大神求助,,,

不愧是大神,逻辑简单但十分准确到位:

#include<bits/stdc++.h>
using namespace std;
int N, K, P;//N给出的数 K因子个数 P因子的指数
vector<int> tem, ans;
int maxFacSum = 0;
void dfs(int start, int dep, int facSum, int powSum){//start起点 dep深度 facSum因子之和 powSum指数之和
if(dep >= K || powSum >= N){
if(dep == K && powSum == N && facSum > maxFacSum){
maxFacSum = facSum;
ans = tem;
}
return;
}
if(start >= 1){
tem.push_back(start);
dfs(start, dep+1, facSum+start, powSum+pow(start*1.0, P*1.0));//选择这个start !!!这里的pow函数不要强制转换为int 会出错
tem.pop_back();
dfs(start-1, dep, facSum, powSum);//未选择当前的start 而是选择更小的数
}
}
int main(){
#ifdef ONLINE_JUDGE
#else
freopen("1.txt", "r", stdin);
#endif // ONLINE_JUDGE

scanf("%d %d %d\n", &N, &K, &P);
dfs((int)pow(N*1.0, 1.0/P)+1, 0, 0, 0);//从P次根号下N从大到小进行选择; +1保证强制转换后不会漏掉数;
if(ans.size() == K){
printf("%d = %d^%d", N, ans[0], P);
for(int i = 1; i < ans.size(); i++)
printf(" + %d^%d", ans[i], P);
}else
printf("Impossible");
return 0;
}

 

对一些必要的地方进行了剪枝:

  • 对因子的最大值进行了限制:
  • *PAT_甲级_1103 Integer Factorization (30point(s)) (C++)【DFS进阶用法】_1103_05

  • 对因子的最大个数dep,和指数之和powSum进行剪枝:
  • *PAT_甲级_1103 Integer Factorization (30point(s)) (C++)【DFS进阶用法】_甲级_06

精妙之处:

  • 使递归从最大的数开始,这样可以避免当因子之和相等时,一个个比较序列中的数字;
  • 适当剪枝;

*PAT_甲级_1103 Integer Factorization (30point(s)) (C++)【DFS进阶用法】_甲级_07

*PAT_甲级_1103 Integer Factorization (30point(s)) (C++)【DFS进阶用法】_DFS进阶用法_08

有种子弹从耳朵👂边飞过的感觉。。。Σ(っ °Д °;)っ

第三搏

打表法!

对不超过N的n^P进行打表,并把结果存储到powValue中,从而避免重复计算数字i的P次方。

每次从powValue中取值:下标即因子,值即因子对应的P次方;

#include<bits/stdc++.h>
using namespace std;
int N, K, P;//N给出的数 K因子个数 P因子的指数
vector<int> tem, ans, powValue;
int maxFacSum = 0;
void initPow(){ //下标对应因子 值对应因子的P次方
powValue.push_back(0);
while(powValue.back() < N)
powValue.push_back(pow(powValue.size(), P)); // !!!妙啊
}
void dfs(int start, int dep, int facSum, int powSum){ //start指向powValue的特定位置 dep深度 facSum因子之和 powSum指数之和
if(dep >= K || powSum >= N){
if(dep == K && powSum == N && facSum > maxFacSum){
maxFacSum = facSum;
ans = tem;
}
return;
}
if(start >= 1){
tem.push_back(start);
dfs(start, dep+1, facSum+start, powSum+powValue[start]); //powValue[start]即start的P次方
tem.pop_back();
dfs(start-1, dep, facSum, powSum); //未选择当前的start 而是选择更小的数
}
}
int main(){
#ifdef ONLINE_JUDGE
#else
freopen("1.txt", "r", stdin);
#endif // ONLINE_JUDGE

scanf("%d %d %d\n", &N, &K, &P);
initPow();
dfs(powValue.size()-1, 0, 0, 0); //从大到小开始选择
if(ans.size() == K){
printf("%d = %d^%d", N, ans[0], P);
for(int i = 1; i < ans.size(); i++)
printf(" + %d^%d", ans[i], P);
}else
printf("Impossible");
return 0;
}

注意:在某些编译环境中,pow函数的取值可能会产生误差。比如代码在codeBlock上运行时,针对样例输出

*PAT_甲级_1103 Integer Factorization (30point(s)) (C++)【DFS进阶用法】_1103_09

(第二搏中的代码,也出现了这样的问题,但是把强制转换去掉后,莫名其妙就OK了)但是,在PTA平台上提交,没有任何问题:

*PAT_甲级_1103 Integer Factorization (30point(s)) (C++)【DFS进阶用法】_DFS进阶用法_10

贼稳!o(* ̄▽ ̄*)ブ

举报

相关推荐

0 条评论