排列枚举 P1706 全排列问题,P1088 火星人 思路: 1.搜索(未学习) 2.STL:next_permutation(start,end) 生成一个在[start,end)内存的数组严格按照字典序的下一个排列,且当为最大值时返回0 I:手写(待补充) 补充: 1.对于全排列的升序输出STL可以轻松解决 2.利用其性质可以求任意第m个排列的后n个排列 课后小题:那么如何倒序输出排列数呢?
子集枚举 P1036 选数(枚举组合并判断) 思路: 1.搜索(未学习) 2.二进制法(对于二进制的初步了解见---) 思路: 1.将每个10进制数当成一个"集合",而0和1代表该元素是否存在 2.利用位运算符逐位判断元素是否存在并符合题意 3.统计各元素是否为指定数目 I:STL直接统计__builtin_popcount()统计二进制下1的个数 II:手写:while(n) cnt += n&1,n >> 1; 4.判定是否为质数(常用的数论知识(入门)见---) 代码: #include <cstdio> #include <iostream> using namespace std; bool check(int x) { if (x == 0 || x == 1) return false; for (int i = 2; i * i <= x; i++) { if (!(x % i)) return false; } return true; } int main() { int a[22],n,k,ans = 0; cin >> n >> k; for (int i = 0; i < n; i++) { scanf("%d", &a[i]); } int U = (1 << n); //U-1为全集 for (int S = 0; S < U; S++) { if (__builtin_popcount(S) == k){ int sum = 0; for (int i = 0; i < n;i++){ if(S&(1 << i)) sum += a[i]; } if(check(sum)) ans++; } } printf("%d", ans); }
P1157 组合数枚举 思路: 1.搜索(未学习) 2.二进制法 I:利于二进制高位依次向低位移动的特点构造集合 II:统计二进制中1的个数后<加工>后输出即可 代码: #include<iostream> #include<algorithm> #include<cstdio> using namespace std; int a[22],n,k; int main() { cin >> n >> k; for (int i = 1; i <= n; i++) { a[i] = i; } int U = (1 << n)-1; 从后往前枚举 for (int S = U; S >= 1; S--) { if (__builtin_popcount(S) == k) { //每次从左往右扫描,利用从高位到低位递减的特征来从小到大输出 //轮不到5 3 2,也不可能(想一想为什么) //从右往左,会很麻烦(想一想在那种情况下会简单?) for (int i = n-1; i >= 0; i--) { if(S&(1 << i)) printf("%3d",n-a[i]); } puts(""); } } } 想一想:你能从大到小输出吗?
朴素暴力及优化 P2241 统计方形(数据加强版) 通用思路: 1.减少重复量(去重) 2.减少枚举量(根据题意缩小范围) 3.更换思路,从其他方面入手(寻找别的突破口,即别的解题特征) 该题思路: 未完待续~
答案:
for (int i = 1; i < n; i++) {if(S&(1 << i)) printf("%3d",n-a[i]);}
“反向利用进位”,同时从右往左进行