打卡:AcWing学习记录1.0

(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 19 分别出现且只出现一次(不包含 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 ,具体是哪里出问题了还不清楚,今晚太晚了,明天再看看是怎么回事。)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值