不是很难, 但这道题的一种算法设计给了我一些启发, 让我进一步理解DFS.
以及搜索树!
以前AC过, 开始靠自己是A不了的, 后来看了题解A掉了
再次写的时候也A掉了, 但方法拙劣了很多, 很暴力的沿用全排列的方法, 有了很多重复计算.
接触搜索不久, 还没有掌握什么剪枝的技巧
思路是:
枚举出所有的排列情况(期中k个数之和可能重复), 最后用组合数学的方法去重
#include <bits/stdc++.h>
using namespace std;
int n, k, num[22], vis[22], cnt = 0, ans = 0;
vector <int> vec;
bool isPrime(int sum)
{
for(int i = 2; i <= sqrt(sum); ++i) {
if(sum % i == 0) return 0;
}
return 1;
}
void dfs()
{
if(cnt == k) {
int sum = 0;
for(int i = 0; i < k; ++i) {
//cout << vec[i] << ' ';
sum += vec[i];
}
//cout << endl;
if(isPrime(sum)) {
ans++;
}
return;
}
for(int i = 1; i <= n; ++i) {
if(vis[i]) continue;
vec.push_back(num[i]);
vis[i] = 1; cnt++;
dfs();
vis[i] = 0; cnt--;
vec.pop_back();
}
}
int main()
{
cin >> n >> k;
for(int i = 1; i <= n; ++i) {
cin >> num[i];
}
dfs();
int tmp = 1;
for(int i = 1; i <= k; ++i) {
tmp *= i;
}
cout << ans/tmp;
}
代码不是很优美
看了我以前做过的(学习借鉴别人的算法), 一时还难以理解.
总觉得用那种方法可能会出现重复, 可它确实是A掉了的
后来突然醒悟过来, 不会重复
我把DFS的过程抽象地(或者说形象的)用搜索树来描述, 最终地答案就是根节点, 而它的值就是其所有子节点的和, 同理, 那些子结点的值也是它们的子结点的和. 直到最简单的那种判断情况.
我觉得写出这种算法的人应该是对DFS理解的非常透彻了.
#include <bits/stdc++.h>
using namespace std;
int num[22], n, k;
bool isPrime(int sum)
{
for(int i = 2; i <= sqrt(sum); ++i)
if(sum%i == 0) return 0;
return 1;
}
//这就是一棵搜索树!
int dfs(int start, int sum, int rem)
{
int ans = 0;
if(rem == 0) return isPrime(sum);
for(int i = start + 1; i <= n; ++i) {
//ans相当于搜索树的结点, 储存情况的种数, 然后向上汇总
ans += dfs(i, sum + num[i], rem - 1);
}
return ans;
}
int main()
{
cin >> n >> k;
for(int i = 1; i <= n; ++i)
cin >> num[i];
cout << dfs(0, 0, k); //从1开始, 还剩n个, 所选数总数
}
这种算法很棒