1. 程式人生 > 實用技巧 >[PAT] A1103 Integer Factorization

[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;
}