2019年9月PAT - 练习笔记——8.1
以下页码标注的是阅读器中实际页码,而不是书本身自印的页码。
第8章 提高篇(2)——搜索专题
8.1 深度优先搜索(DFS)
注意
- 可以考虑对某些数据进行预处理,从而提高效率
目录
- A1103 Integer Factorization
-
A1103 Integer Factorization
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 thei
-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
-
我的
#include <iostream> #include <cmath> #include <vector> using namespace std; int n = 0, k = 0, p = 0; int nowSum = 0; vector<int> factors, sequences; bool flag = false; void Find(int now, int sum) { if (now == k) { if (sum == n) { if (sequences.empty()) { sequences = factors; for (int i = 0;i < k;++i) nowSum += factors[i]; } else { int tmp = 0; for (int i = 0;i < k;++i) tmp += factors[i]; if (tmp > nowSum) { nowSum = tmp; sequences = factors; } else if (tmp == nowSum && factors > sequences) sequences = factors; } flag = true; } return; } for (;factors[now] <= factors[now - 1];++factors[now]){ int tmp = sum + pow(factors[now], p); if (tmp <= n) Find(now + 1, tmp); } factors[now] = 1; } int main(void) { scanf("%d %d %d", &n, &k, &p); factors.resize(k, 1); factors[0] = pow(n - (k - 1), 1 / (float)p); int end = pow((float)n / k, 1 / (float)p); for (;factors[0] >= end;--factors[0]) Find(1, pow(factors[0], p)); if (!flag) printf("Impossible"); else { printf("%d = %d^%d", n, sequences[0], p); for (int i = 1;i < k;++i) printf(" + %d^%d", sequences[i], p); } return 0; }
这题我记得当初写了好久……这次提交一遍过!超级开心!
但我的算法不是很好,参考代码写的比较好
-
《算法笔记》P286
-
“由于P不小于2,并且在单次运算中是固定的,因此不妨开设一个vector fac,在读入P之后就预处理所有不超过N的np。为了方便下标与元素有直接的对应,这里应把0也存进去。于是对N = 10、P = 2来说,fac[0] = 0, fac[1] = 1, fac[2] = 4, fac[3] = 9。”
-
“为了让结果能保证字典序大的序列优先被选中,让index从大到小递减来遍历,这样就总是能先选中fac中较大的数了。
显然,如果当前需要对fac[index]进行选择,那么就会有“选”与“不选”两种选择。如果不选,就可以把问题转化为对fac[index - 1]进行选择……而如果选,由于每个数字可以重复选择,因此下一步还应当对fac[index]进行选择……”
#include <cstdio> #include <vector> #include <algorithm> using namespace std; int n, k, p, maxFacSum = -1; vector<int> fac, ans, temp; int power(int x) { int ans = 1; for (int i = 0;i < p;i++) ans *= x; return ans; } void init() { int i = 0, temp = 0; while (temp <= n) { fac.push_back(temp); temp = power(++i); } } void DFS (int index, int nowK, int sum, int facSum) { if (sum == n && nowK == k) { if (facSum > maxFacSum) { ans = temp; maxFacSum = facSum; } return; } if (sum > n || nowK > k) return; if (index - 1 >= 0) { temp.push_back(index); DFS(index, nowK + 1, sum + fac[index], facSum + index); // "选"的分支 temp.pop_back(); DFS(index - 1, nowK, sum, facSum); // “不选”的分支 } } int main() { scanf("%d%d%d", &n, &k, &p); init(); DFS(fac.size() - 1, 0, 0, 0); if (maxFacSum == -1) printf("Impossible\n"); else { printf("%d = %d^%d", n, ans[0], p); for (int i = 1;i < ans.size();i++) printf(" + %d^%d", ans[i], p); } return 0; }
-
-