深度优先搜索生成排列与组合
/*枚举可重复排列模板*/ #include<iostream> using namespace std; int n, m, ans[15]; int a[15];//待选数据 void dfs(int index)//输出n个数选m个数的所有排列 { if (index == m) { for (int i = 0; i < m; i++) printf("%d ", ans[i]); printf("\n"); return; } for (int i = 0; i < n; i++) { ans[index] = a[i]; dfs(index + 1); } } int main() { while (scanf("%d %d", &n, &m) != EOF) { for (int i = 0; i < n; i++) scanf("%d", &a[i]); dfs(0); } return 0; }
运行实例:
/*从n个数选出m个数 生成不可重复的排列,加标记数组即可*/ #include<iostream> using namespace std; int n, m, ans[15]; int a[15];//待选数 bool vis[15]; void dfs(int index) { if (index == m) { for (int i = 0; i < m; i++) printf("%d ", ans[i]); printf("\n"); return; } for (int i = 0; i < n; i++) { if (!vis[i]) { ans[index] = a[i]; vis[i] = 1; dfs(index + 1); vis[i] = 0; } } } int main() { while (scanf("%d %d", &n, &m) != EOF) { fill(vis, vis + 15, 0); for (int i = 0; i < n; i++) scanf("%d",&a[i]); dfs(0); } return 0; }
运行实例
/*枚举组合*/ #include<iostream> using namespace std; int n, m, ans[15]; int a[15];//待选数 void dfs(int d, int index) { if (index == m) { for (int i = 0; i < m; i++) printf("%d ", ans[i]); printf("\n"); return; } for (int i = d; i < n; i++) { ans[index] = a[i]; dfs(i + 1, index + 1); } } int main() { while (scanf("%d %d", &n, &m) != EOF) { for (int i = 0; i < n; i++) scanf("%d", &a[i]); dfs(0, 0); } return 0; }
运用dfs考题
一个袋子里面有n个球,每个球上面都有一个号码(拥有相同号码的球是无区别的)。如果一个袋子是幸运的当且仅当所有球的号码的和大于所有球的号码的积。
例如:如果袋子里面的球的号码是{1, 1, 2, 3},这个袋子就是幸运的,因为1 + 1 + 2 + 3 > 1 * 1 * 2 * 3
你可以适当从袋子里移除一些球(可以移除0个,但是别移除完),要使移除后的袋子是幸运的。现在让你编程计算一下你可以获得的多少种不同的幸运的袋子。
#include <iostream> #include <stdlib.h> using namespace std; int n; int nums[1000]; int cmp(const void * a, const void * b) { return *(int*)a - *(int*)b; } // 思路:DFS生成全组合,同时注意剪枝、避免重复组合 int findall(int nums[], int d, long sum, long multi) { int count = 0; for(int i=d; i<n; i++) { sum += nums[i]; multi *= nums[i]; if(sum > multi) count += 1 + findall(nums, i+1, sum, multi); else if(nums[i] == 1) count += findall(nums, i+1, sum, multi); else break; sum -= nums[i]; multi /= nums[i]; // 跳过相等的元素,避免重复组合 while(i<n-1 && nums[i]==nums[i+1]) i++; } return count; } int main(int argc, char* argv[]) { while(cin >> n) { for(int i=0; i<n; i++) cin >> nums[i]; // 从小到大排序 qsort(nums, n, sizeof(int), cmp); cout << findall(nums, 0, 0, 1) << endl; } return 0; }
配合思考题 bfs 广度优先搜索
小易总是感觉饥饿,所以作为章鱼的小易经常出去寻找贝壳吃。最开始小易在一个初始位置x_0。对于小易所处的当前位置x,他只能通过神秘的力量移动到 4 * x + 3或者8 * x + 7。因为使用神秘力量要耗费太多体力,所以它只能使用神秘力量最多100,000次。贝壳总生长在能被1,000,000,007整除的位置(比如:位置0,位置1,000,000,007,位置2,000,000,014等)。小易需要你帮忙计算最少需要使用多少次神秘力量就能吃到贝壳。
#include <bits/stdc++.h> using namespace std; #define MOD 1000000007LL #define MAX 100000 int main(){ unordered_map<long long,int> vist; for(long long x;cin>>x;vist.clear()){ queue<long long> q; for(long long xx=vist[x]=1,q.push(x);q.size();){ x = q.front(); q.pop(); if (x==0) break; if (vist[x]>MAX) continue; xx=((x<<2)+3)%MOD; if (vist.find(xx)==vist.end()) { q.push(xx); vist[xx]=vist[x]+1; } xx=((x<<3)+7)%MOD; if (vist.find(xx)==vist.end()){ q.push(xx); vist[xx]=vist[x]+1; } } cout<<(q.size()?vist[x]-1:-1)<<endl; } return 0; }