已知n+1个正数:w i (1<=i<=n)和M,要求找出{w i }的所有子集使得子集中元素之和等于M。解采用可变长的k-元组(x 1 ,...,x k ) 表达,其中:x i ∈{1, ..n},表示被选中的数值w的下标,1<=i<=k。隐式约束条件是选中的数值和数为M,x i 相互不同,且按取值从小到大顺序排列。 要求利用FIFO分支限界方法解决子集和数问题。 输入格式: 第一行为一个不超过200的正整数n,表示总集规模; 第二行是正整数M,表示子集的和数; 第三行是总集中n个正整数,中间用空格隔开。 输出格式: 如果有答案,则输出所有满足条件的子集(用可变长度数组表示符合条件的一个子集,子集中元素表示被选中的数值的下标); 如果没有答案,则输出“no solution!”。给出一份C++代码
时间: 2024-03-19 10:43:58 浏览: 182
海康威视DS-8632N-I16最新固件,版本 V4.61.025 build 220905
下面是使用FIFO分支限界方法求解子集和数问题的C++代码实现:
```c++
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
const int N = 205;
int n, m;
int w[N];
bool st[N][N];
struct Node
{
int sum;
int k;
int path[N];
bool operator < (const Node& t) const
{
return sum < t.sum;
}
};
void bfs()
{
priority_queue<Node> q;
Node root = {0, 0};
q.push(root);
while (q.size())
{
Node t = q.top();
q.pop();
if (t.sum == m)
{
for (int i = 1; i <= t.k; i ++ )
cout << t.path[i] << " ";
cout << endl;
continue;
}
if (t.k == n) continue;
if (t.sum + w[t.k + 1] <= m && !st[t.k + 1][t.sum + w[t.k + 1]])
{
Node a = t;
a.sum += w[a.k + 1];
a.k ++ ;
a.path[a.k] = a.k;
q.push(a);
st[a.k][a.sum] = true;
}
if (!st[t.k + 1][t.sum])
{
Node b = t;
b.k ++ ;
q.push(b);
st[b.k][b.sum] = true;
}
}
}
int main()
{
cin >> n >> m;
for (int i = 1; i <= n; i ++ ) cin >> w[i];
memset(st, false, sizeof st);
bfs();
if (!st[n][m]) cout << "no solution!" << endl;
return 0;
}
```
在上述代码中,我们使用了一个优先队列来维护当前搜索状态,每次取出队列中的最小元素进行扩展。
我们使用Node结构体来表示当前搜索状态,sum表示当前状态对应的子集和数,k表示当前状态对应的选中的元素个数,path数组表示当前状态对应的选中的元素下标。
在bfs函数中,首先初始化初始状态,并将其加入优先队列中。然后,当队列不为空时,取出队列中的最小元素进行扩展。如果当前状态对应的子集和数等于目标数m,则输出对应的解,并继续搜索其他解;否则,分别考虑选中或不选中当前元素的两种情况,并将扩展出的状态加入队列中。
需要注意的是,在扩展状态时,需要判断当前状态是否已经被扩展过,如果被扩展过,则直接跳过。
如果找不到符合要求的解,则输出“no solution!”。
时间复杂度:O(nmlog(nm))。
阅读全文