一.深度优先搜索
枚举所有完整路径以遍历所有情况;
实现方式:递归 / 非递归;
示例一:
void DFS(int index, int sumW, int sumC) {
//终点:
if(index == n) return;
//不选第 index 件物品:
DFS(index + 1, sumW, sumC);
//选第 index 件物品:
if(w[index] + sumW <= V) {
if(sumC + c[index] > ans) ans = sumC + c[index];
DFS(index + 1, sumW + w[index], sumC + c[index]);
}
}
示例二:
(1).
void DFS(int index, int nowK, int sum, int sumSqu) {
//有效终点:
if(nowK == K && sum == X) {
if(sumSqu > Squ) {
Squ = sumSqu;
ans = temp;
}
return;
}
//无效终点:
if(index == n || nowK > K || sum > X) return;
//选第 index 个数:
temp.push_back(s[index]);
DFS(index + 1, nowK + 1, sum + s[index], sumSqu + s[index] * s[index]);
temp.pop_back();
//不选第 index 个数:
DFS(index + 1, nowK, sum, sumSqu);
}
注意:
1).选第 index 个数时,先把 s[index] 放进 temp 里,进入“选 s[index] ”这条分支;当这条分支结束时,把 s[index] 从 temp 中拿出来,使它不会影响“不选 s[index] ”这条分支;
2).两个岔路位置不可以颠倒,为什么?
(2).
假设题目中的 N 个整数均可以被选择多次,则将DFS(index + 1, nowK + 1, sum + s[index], sumSqu + s[index] * s[index]);
替换成DFS(index, nowK + 1, sum + s[index], sumSqu + s[index] * s[index]);
即可;
二.题目
1.PAT A1103
思路:
和示例二(2)一样;
注意:
1).保证底数字典序最大:让 index 从小到大遍历;
2).不能从 N 开始遍历,会超时;必须从 n ^ P <= N 的数处开始(比如169 5 2,index = 13);计算 n 的方法不能是 pow(N, 1 / P),因为 1 / P 会是0;
代码:
#include<cstdio>
#include<vector>
#include<cmath>
using namespace std;
const int maxn = 420;
int N, K, P;
vector<int> ans;
vector<int> temp;
int maxSumFac = 0;
void DFS(int index, int nowK, int sum, int sumFac) {
if(nowK == K && sum == N) {
if(sumFac > maxSumFac) {
maxSumFac = sumFac;
ans = temp;
}
return;
}
if(sum > N || nowK > K || index - 1 < 0) return;
temp.push_back(index);
DFS(index, nowK + 1, sum + pow(index, P), sumFac + index);
temp.pop_back();
DFS(index - 1, nowK, sum, sumFac);
}
int main() {
scanf("%d%d%d", &N, &K, &P);
int n;
for(n = 1; n <= N; n++) {
if(pow(n, P) > N) break;
}
n = n - 1;
DFS(n, 0, 0, 0);
if(ans.size() == 0) printf("Impossible\n");
else {
printf("%d = ", N);
for(int i = 0; i < ans.size(); i++) {
if(i == ans.size() - 1) printf("%d^%d\n", ans[ans.size() - 1], P);
else printf("%d^%d + ", ans[i], P);
}
}
return 0;
}