题目链接: 递归实现指数型枚举
解题思路:
- dfs
state | 1 << u:将第u位设置为1,表示当前u包含在子集当中
- 1 << u: 这是一个左移操作,表示将数字 1 左移 u 位。左移 u 位相当于在 1 后面加上 u 个 0。例如,1 << 0 是 1(二进制 0001),1 << 1 是 2(二进制 0010),1 << 2 是 4(二进制 0100),依此类推。这个操作的结果是一个只有第 u 位是 1 的数,其余位都是 0。
- state | (1 << u): 这是一个按位或操作,表示将 state 的二进制表示与 1 << u 的结果按位或。按位或操作的规则是:如果某一位上有一个 1,结果在该位上就是 1。例如,假设 state 是 5(二进制 0101),u 是 1,那么 1 << 1 是 2(二进制 0010)。按位或操作 0101 | 0010 的结果是 0111,即 7。
#include<iostream>
using namespace std;
int n;
void dfs(int u, int state){//从第0个数开始枚举,state表示状态
if(u == n){
//当前所有数字都被考虑过了,输出当前子集并返回
for(int i = 0; i < n; i++){//输出当前子集:0 - n-1的所有位
if(state >> i & 1){ //检查state的第i位是否为1,如果是输出对应的数字 i+1
cout << i + 1 << ' ';
}
}
cout << endl;
return;
}
dfs(u + 1, state);//不包含当前数字u,直接进入下一层递归
dfs(u + 1 , state | 1 << u);//包含当前数字,将u对应位设置为1,然后进入下一层递归
}
int main(){
cin >> n;
dfs(0, 0);
return 0;
}
题目链接:递归实现组合型枚举
思路分析:
-
dfs
-
限制了输出的个数
-
考虑边界条件
#include<iostream>
using namespace std;
int n, m;
void dfs(int u, int sum, int state){
if(sum + n - u < m){// 当前选择的数字 + 没选的所有数字 都不够m个数字,直接返回
return;
}
if(sum == m){
for(int i = 0; i < n; i++){
if(state >> i & 1){
cout << i + 1 << " ";
}
}
cout << endl;
return;
}
//已经遍历n个了,还没有找到合法的情况,直接返回
if(u == n){
return;
}
dfs(u + 1, sum + 1, state | 1 << u);//先选:题目要求从小到大输出
dfs(u + 1, sum, state);
}
int main(){
cin >> n >> m;
dfs(0, 0, 0);// 枚举了多少个数字,当前选了多少数字,当前选了哪些数
return 0;
}
题目链接:递归实现排列型枚举
解题思路:
相当于有n个坑位,填充坑位的时候,从当前没有选择的数字中进行选择,直到将n个数字都放入n个坑位当中为之。
#include<iostream>
#include<vector>
using namespace std;
int n;
vector<int> path;
void dfs(int u, int state){
if(u == n){
for(auto x : path){
cout << x << ' ';
}
cout << endl;
return;
}
for(int i = 0; i < n; i++){
if(!(state >> i & 1)){//该数字没有枚举过
path.push_back(i + 1);
dfs(u + 1, state | 1 << i);//将该位置标记已经访问(二进制位置1),进入下一个位置的判断
path.pop_back();// 恢复现场
}
}
}
int main(){
cin >> n;
dfs(0, 0);//从第0个数字开始枚举 每个数字是否选过用一个数字的二进制表示
return 0;
}
题目链接:激光炸弹
解题思路
- 前缀和
#include<iostream>
using namespace std;
const int N = 5010;
int g[N][N];
int n,m,w,r;
int main()
{
cin >> n >> r;
int x,y,w;
for(int i=0;i<n;i++){
cin >> x >> y >> w;
g[x+1][y+1]+=w;
}
for(int i=1;i<=5001;i++){
for(int j=1;j<=5001;j++){
g[i][j]=g[i-1][j]+g[i][j-1]-g[i-1][j-1]+g[i][j];
}
}
int ans=0;
if(r>=5000){
cout<<g[5001][5001]<<endl;
return 0;
}
for(int i=r;i<=5001;i++){
for(int j=r;j<=5001;j++){
ans=max(ans,g[i][j]-g[i-r][j]-g[i][j-r]+g[i-r][j-r]);
}
}
cout<<ans<<endl;
return 0;
}