2021牛客暑期多校训练营3 F.24dian 暴搜dfs

这篇博客主要介绍了一道数学竞赛题目,要求使用[1,13]范围内的卡片通过加减乘除操作得出特定数值m。作者提到当卡片数量小于等于3时无法找到解决方案,并提供了详细的四层循环枚举算法来查找所有可能的组合。在算法中,先对卡片排序并利用vis数组避免重复计算,然后通过递归检查每一步操作是否涉及分数运算。最后,博主给出了一个可行解的数量及其具体组合。
摘要由CSDN通过智能技术生成

原题链接:https://ac.nowcoder.com/acm/contest/11254/F

题意

用n张[1,13]的卡片凑出m,可以用加减乘除操作,要求可行的方案在运算中必须出现分数,最后计算出总方案数并输出。

分析

由于数据量不大,直接枚举就可以了。值得注意的是,n在<=3的情况下是肯定无解的。我们只要四层for循环去枚举所有卡片,然后判断是否可行。有一个优化的小技巧,我们先把四张卡片排序,然后用vis数组储存,如果遍历过直接跳过即可。

然后看怎么判断是否可行,刚开始有n张卡,我们暴力枚举两个数,对它们进行操作,然后放回数组,递归求解,如果有一组解可以不通过分数运算得到答案,我们就返回不可行。

Code

#include <bits/stdc++.h>
#define lowbit(i) i & -i
#define Debug(x) cout << x << endl
#define fi first
#define se second
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
const ll INF = 1e18;
const double eps = 1e-3;
const int N = 1e5 + 10;
const int M = 1e6 + 10;
const int MOD = 998244353;
struct node {
    int x1, x2, x3, x4;
};
vector<node> ans;
bool check(double x) {//是否出现分数
    return fabs(int(x) - x) > eps;
}
int ff = 0, f = 0;
int vis[15][15][15][15];
void dfs(vector<double> a, int b, bool flag) {
    if (a.size() == 1) {
        if (fabs(a[0] - b) < eps) {
            if (!flag) ff = 1;
            f = 1;
        }
        return;
    }
    for (int i = 0; i < a.size(); i++) {
        for (int j = 0; j < a.size(); j++) {
            if (i == j) continue;
            vector<double> tmp = a;
            double tmp1 = a[i], tmp2 = a[j];
            a.erase(a.begin() + max(i, j));
            a.erase(a.begin() + min(i, j));
            a.push_back(tmp1 + tmp2);
            dfs(a, b, flag | check(tmp1 + tmp2));

            a = tmp;
            a.erase(a.begin() + max(i, j));
            a.erase(a.begin() + min(i, j));
            a.push_back(tmp1 * tmp2);
            dfs(a, b, flag | check(tmp1 * tmp2));

            if (tmp2 != 0) {
                a = tmp;
                a.erase(a.begin() + max(i, j));
                a.erase(a.begin() + min(i, j));
                a.push_back(tmp1 / tmp2);
                dfs(a, b, flag | check(tmp1 / tmp2));
            }

            a = tmp;
            a.erase(a.begin() + max(i, j));
            a.erase(a.begin() + min(i, j));
            a.push_back(tmp1 - tmp2);
            dfs(a, b, flag | check(tmp1 - tmp2));

            a = tmp;
        }
    }
}
void solve() {
    int n, m; cin >> n >> m;
    if (n <= 3) {
        cout << 0 << endl;
        return;
    }

    for (int a = 1; a <= 13; a++) {
        for (int b = 1; b <= 13; b++) {
            for (int c = 1; c <= 13; c++) {
                for (int d = 1; d <= 13; d++) {
                    vector<double> v;
                    v.push_back(a);
                    v.push_back(b);
                    v.push_back(c);
                    v.push_back(d);
                    sort(v.begin(), v.end());
                    if (vis[(int)v[0]][(int)v[1]][(int)v[2]][(int)v[3]]) continue;
                    vis[(int)v[0]][(int)v[1]][(int)v[2]][(int)v[3]] = 1;
                    ff = f = 0;
                    dfs(v, m, false);
                    if (f && !ff) ans.push_back({a, b, c, d});

                }
            }
        }
    }
    cout << ans.size() << endl;
    for (auto it : ans) {
        cout << it.x1 << " " << it.x2 << " " << it.x3 << " " << it.x4 << endl;
    }
}
signed main() {
    ios_base::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
#ifdef ACM_LOCAL
    freopen("input", "r", stdin);
    freopen("output", "w", stdout);
    signed test_index_for_debug = 1;
    char acm_local_for_debug = 0;
    do {
        if (acm_local_for_debug == '$') exit(0);
        if (test_index_for_debug > 20)
            throw runtime_error("Check the stdin!!!");
        auto start_clock_for_debug = clock();
        solve();
        auto end_clock_for_debug = clock();
        cout << "Test " << test_index_for_debug << " successful" << endl;
        cerr << "Test " << test_index_for_debug++ << " Run Time: "
             << double(end_clock_for_debug - start_clock_for_debug) / CLOCKS_PER_SEC << "s" << endl;
        cout << "--------------------------------------------------" << endl;
    } while (cin >> acm_local_for_debug && cin.putback(acm_local_for_debug));
#else
    solve();
#endif
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值