(ps.学习打卡记录)
1 . 递归实现指数型枚举
题意:从 1~n 这 n 个整数中随机选取任意多个,输出所有可能的选择方案。
递归搜索实现枚举所有方案,限制搜索顺序为从小到大保证字典序。
附代码
#include <bits/stdc++.h>
using namespace std;
int n,vis[17] = {0};
void dfs(int cur, int num, int dis) {
vis[cur] = dis;
if (num == n) {
for (int i = 1; i <= n; ++i) {
if (vis[i]) cout << i << ' ';
}
cout << '\n';
}
for (int i = cur + 1; i <= n; ++i) {
dfs(i, num + 1, 0);
dfs(i, num + 1, 1);
}
}
int main() {
cin >> n;
dfs(0, 0, 0);
return 0;
}
2 . 递归实现排列型枚举
题意:把 1~n 这 n 个整数排成一行后随机打乱顺序,输出所有可能的次序。
递归搜索实现枚举所有方案,限制从大到小搜索满足字典序。
附代码
#include<iostream>
#include<vector>
using namespace std;
int n;
bool vis[10]={false};
vector<int>ans;
void dfs(int num){
if(num==n) for(int i=0;i<n;++i) cout<<ans[i]<<(i+1==n?'\n':' ');
for(int i=1;i<=n;++i){
if(!vis[i]){
vis[i]=true;
ans.push_back(i);
dfs(num+1);
ans.pop_back();
vis[i]=false;
}
}
}
int main(){
cin>>n;
dfs(0);
return 0;
}
3 . 递归实现组合型枚举
题意:从 1~n 这 n 个整数中随机选出 m 个,输出所有可能的选择方案。
递归搜索所有方案数。
附代码
#include <bits/stdc++.h>
using namespace std;
int n, m,vis[30] = {0};
vector<int> ans;
void dfs(int cur, int num) {
if (num == m) {
for (int i = 0; i < m; ++i) cout << ans[i] << ' ';
cout << '\n';
}
for (int i = cur + 1; i <= n; ++i) {
if (!vis[i]) {
vis[i] = true;
ans.emplace_back(i);
dfs(i, num + 1);
ans.pop_back();
vis[i] = false;
}
}
}
int main() {
cin >> n >> m;
dfs(0, 0);
return 0;
}
4 . 带分数
题意: 100 100 100 可以表示为带分数的形式: 100 = 3 + 69258 714 100=3+\frac{69258}{714} 100=3+71469258,还可以表示为: 100 = 82 + 3546 197 100=82+\frac{3546}{197} 100=82+1973546,注意特征:带分数中,数字 1 ∼ 9 1∼9 1∼9 分别出现且只出现一次(不包含 0 0 0 ),给定正整数 n n n ,问有多少种方案。
可以表示为 n = a + b c n=a+\frac bc n=a+cb ,变形成 n c = a c + b nc=ac+b nc=ac+b,枚举 a a a 和 c c c 即可,然后由于每个数字只能出现一次,所以可以用递归实现组合型枚举,每枚举一个 a a a 就在其后接着枚举 c c c ,计算出 b b b 之后检查每个数字出现次数,统计方案数。
附代码
#include <bits/stdc++.h>
using namespace std;
int n, ans = 0,vis[30] = {0},visbackup[30] = {0};
bool check(int a, int c) {
int b = n * c - c * a;
if (!a || !b || !c) return false;
memcpy(visbackup, vis, sizeof(vis));
while (b) {
int x = b % 10;
b /= 10;
if (!x || vis1[x]) return false;
vis1[x] = true;
}
for (int i = 1; i <= 9; ++i) {
if (!vis1[i]) return false;
}
return true;
}
void dfs_c(int num, int a, int c) {
if (num == 9) return;
if (check(a, c)) ans++;
for (int i = 1; i <= 9; ++i) {
if (!vis[i]) {
vis[i] = true;
dfs_c(num + 1, a, c * 10 + i);
vis[i] = false;
}
}
}
void dfs_a(int num, int a) {
if (a >= n) return;
dfs_c(num + 1, a, c);
for (int i = 1; i <= 9; ++i) {
if (!vis[i]) {
vis[i] = true;
dfs_a(num + 1, a * 10 + i);
vis[i] = false;
}
}
}
int main() {
cin>>n;
dfs_a(0,0);
cout<<ans<<endl;
return 0;
}
5 . 费解的开关
题意:25 盏灯排成一个 5 × 5 5\times5 5×5 的方形。每一个灯都有一个开关,游戏者可以改变它的状态。每一步,游戏者可以改变某一个灯的状态。游戏者改变一个灯的状态会产生连锁反应:和这个灯上下左右相邻的灯也要相应地改变其状态,其中 0 表示关,1 表示开。问最少几步能把 25 盏灯全部打开,若大于 6 步,则输出 − 1 -1 −1 。
经过分析可以得知,当对第一行的灯进行操作后,为了保持第一行灯始终亮着,对下一行灯的操作位置就已经确定了,类推下去,可以仅由第一行的操作决定 25 盏灯的状态,所以枚举第一行灯的所有操作方案即可。由于只有两种状态,所以可以采用二进制枚举,每一位表示对应位置上灯的状态。
附代码
#include <bits/stdc++.h>
using namespace std;
char backup[7][7], g[7][7];
void turn(int x, int y) {
int dx[5] = {0, -1, 0, 0, 1};
int dy[5] = {-1, 0, 1, 0, 0};
for (int i = 0; i < 5; ++i) {
int a = x + dx[i], b = y + dy[i];
if (a < 0 || a > 4 || b < 0 || b > 4) continue;
if (backup[a][b] == '0') backup[a][b] = '1';
else backup[a][b] = '0';
}
}
int main() {
int T;
cin >> T;
while (T--) {
for (int i = 0; i < 5; ++i) cin >> g[i];
int ans = 13;
for (int i = 0; i < 32; ++i) {
int step = 0;
memcpy(backup,g, sizeof(g));
for (int j = 0; j < 5; ++j) {
if (i >> j & 1) {
step++;
turn(0, j);
}
}
for (int j = 0; j < 4; j++) {
for (int k = 0; k < 5; ++k) {
if (backup[j][k] == '0') {
step++;
turn(j + 1, k);
}
}
}
int flag = 1;
for (int i = 0; i < 5; ++i) {
if (backup[4][i] == '0') flag = 0;
}
if (flag) ans = min(step, ans);
}
if (ans > 6)cout << -1 << endl;
else cout << ans << endl;
}
return 0;
}
(ps . 最后一题 d e b u g debug debug 了 20 20 20 多分钟,每次翻转备份数组时都会改变原数组的值,一直没搞懂为什么,然后试着将 s t r i n g b a c k u p [ 7 ] string\ backup[7] string backup[7] 改成 c h a r b a c k u p [ 7 ] [ 7 ] char\ backup[7][7] char backup[7][7] 就没问题了,之前无论使用 m e m c p y ( ) memcpy() memcpy() 还是循环来备份都不行,设置成全局或者局部变量也有 b u g bug bug ,具体是哪里出问题了还不清楚,今晚太晚了,明天再看看是怎么回事。)