PTA:子集和问题(c++)

题目

设集合S={x1,x2,…,xn}是一个正整数集合,c是一个正整数,子集和问题判定是否存在S的一个子集S1,使S1中的元素之和为c。试设计一个解子集和问题的回溯法,并输出利用回溯法在搜索树(按输入顺序建立)中找到的第一个解。

输入格式:

输入数据第1行有2个正整数n和c,n表示S的大小,c是子集和的目标值。接下来的1行中,有n个正整数,表示集合S中的元素。
是子集和的目标值。接下来的1 行中,有n个正整数,表示集合S中的元素。

输出格式:

输出利用回溯法找到的第一个解,以空格分隔,最后一个输出的后面有空格。当问题无解时,输出“No Solution!”。

输入样例:

在这里给出一组输入。例如:

5 10
2 2 6 5 4

输出样例:

在这里给出相应的输出。例如:

2 2 6 

 思路:

题目要求得到第一个满足条件的解就行,则可以利用回溯法,来进行解决。

也就是从第一个数开始,慢慢叠加,直到遇到第一个可行解,同时也要优化一下,否则会超时。

代码:

#include <bits/stdc++.h>
#define lsl(i, a, b) for (int i = a; i < b; i++)
#define hxy(i, a, b) for (int i = a; i <= b; i++)
#define pii pair<int, int>
#define ios ios::sync_with_stdio(0), cin.tie(0), cout.tie(0)
#define inf 0x3f3f3f3f
#define ll long long
#define re register
#define endl "\n"
using namespace std;
// 一些无关紧要的宏定义
const int N = 1e6 + 5;
int n, m;
int a[N], vis[N];          // 一个存数的数组, 一个标记数组
bool is = false;           // 判断是否有可行解
void dfs(int x, int sum) { // x代表下标,sum是此时的值
    if (is) return;        // 剪枝,找到一个解后直接return,避免超时
    if (sum == m) {        // 找了一个解
        is = true;
        return;
    }
    lsl(i, x, n) { // 循环加数、回溯
        if (!vis[i] && sum + a[i] <= m) {
            vis[i] = 1;
            dfs(i + 1, sum + a[i]);
            if (is) return;
            vis[i] = 0;
        }
    }
}
void solve() {
    cin >> n >> m;
    int sum = 0;
    lsl(i, 0, n) cin >> a[i], sum += a[i]; // 前缀和优化,必须有否则会有部分测试点超时
    if (sum < m)
        cout << "No Solution!";
    else if (sum == m)
        lsl(i, 0, n) cout << a[i] << " ";
    else { // 回溯求解
        dfs(0, 0);
        if (is) {
            lsl(i, 0, n) if (vis[i]) cout << a[i] << " ";
        } else
            cout << "No Solution!";
    }
}
int main() {
    ios;
    solve();
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值