[PAT] A1103 Integer Factorization
(dfs深度優先搜尋)
思路
先把i從0開始所有的i的p次方的值儲存在v[i]中,直到v[i] > n為止。(如果在遞迴過程中計算次方,會做很多重複工作,很浪費時間。)
然後深度優先搜尋,記錄當前正在相加的index(即v[i]的i的值),當前的總和tempSum,當前K的總個數tempK,以及因為題目中要求輸出因子的和最大的那個,所以儲存一個facSum為當前因子的和,讓它和maxFacSum比較,如果比maxFacSum大就更新maxFacSum和要求的ans陣列的值。
在ans數組裡面儲存因子的序列,tempAns為當前深度優先遍歷而來的序列,從v[i]的最後一個index開始一直到index == 1,因為這樣才能保證ans和tempAns數組裡面儲存的是從大到小的因子的順序。
一開始maxFacSum == -1,如果dfs後maxFacSum並沒有被更新,還是-1,那麼就輸出Impossible,否則輸出答案。
剪枝:
1.tempK==K但是tempSum!=n的時候需要剪枝
2.在列舉的時候,按順序列舉,上界或者下界可進行剪枝
3.當且僅當tempSum + v[index] <= n時,進行下一層的DFS,而不要進入下一層DFS發現不滿足條件再返回,這樣開銷會比較大
4.每次temv的push_back、pop_back都需要重新分配記憶體空間,比較耗時,由於答案的序列長度是確定的,可以將ans序列初始化為定長的,這樣在遞迴的過程中就不需要push、pop; pow的計算結果可以儲存下來,以免重複計算,耗用多餘的時間
坑
1.要先存好次方計算後的值,避免遞迴時重複計算。
2.直接利用maxsum來判斷是否有解,通過設初值為負數。無需額外建立標記判斷。
3.倒著遞迴,從大數開始判斷。
AC程式碼
#define _CRT_SECURE_NO_WARNINGS #include<cstdio> #include<iostream> #include<vector> #include<algorithm> #include<cmath> using namespace std; #define MAX 500 int n, k, p, maxsum = -1; vector<int>v; vector<int>solution, maxsolution; void optmax() { int i = 0; while (solution[i] == maxsolution[i])i++; if (solution[i] > maxsolution[i]) maxsolution = solution; } void DFS(int index, int count, int ans, int sum) { if (count == k && ans == n) { if (maxsum < sum) { maxsum = sum; maxsolution = solution; } else if (maxsum == sum) optmax(); //此處可以不用判斷相等情況,也能AC。 return; } if (index == 0 || ans > n || count >= k)return; if (ans + v[index] <= n) { solution.push_back(index); DFS(index, count + 1, ans + v[index], sum + index); solution.pop_back(); } DFS(index - 1, count, ans, sum); } int main() { scanf("%d%d%d", &n, &k, &p); int temp = 0, index = 1; while (temp <= n) { v.push_back(temp); temp = pow(index, p); index++; } DFS(v.size() - 1, 0, 0, 0); if (maxsum < 0)printf("Impossible"); else { printf("%d = %d^%d", n, maxsolution[0], p); for (int i = 1; i < k; i++) printf(" + %d^%d", maxsolution[i], p); } return 0; }
另
如果改成正著來,測試點5就超時了...實在想不通是什麼回事,希望走過路過的大神們幫我看看,感激不盡!!!
(我想應該是從大數開始比較容易到達邊界,減少了遞迴次數)
#define _CRT_SECURE_NO_WARNINGS #include<cstdio> #include<iostream> #include<vector> #include<map> #include<algorithm> #include<cmath> using namespace std; #define MAX 500 int n, k, p, maxsum = -1; vector<int>v; vector<int>solution, maxsolution; bool cmp(int a, int b) { return a > b; } void optmax() { int i = 0; while (solution[i] == maxsolution[i])i++; if (solution[i] > maxsolution[i]) maxsolution = solution; } void DFS(int index, int count, int ans, int sum) { if (count == k && ans == n) { if (maxsum < sum) { maxsum = sum; maxsolution = solution; } else if (maxsum == sum) optmax(); return; } if (index >= v.size() || ans > n || count >= k)return; if (ans + index <= n) { solution[count] = index; DFS(index, count + 1, ans + v[index], sum + index); } DFS(index + 1, count, ans, sum); } int main() { scanf("%d%d%d", &n, &k, &p); solution.resize(k); int temp = 0, index = 1; while (temp <= n) { v.push_back(temp); temp = pow(index, p); index++; } DFS(1, 0, 0, 0); if (maxsum < 0)printf("Impossible"); else { printf("%d = %d^%d", n, maxsolution[k - 1], p); for (int i = k - 2; i >= 0; i--) printf(" + %d^%d", maxsolution[i], p); } return 0; }