给定一个n元1次方程: c 1 x 1 + c 2 x 2 + . . . + c n x n = b c_1x_1+c_2x_2+...+c_nx_n=b c1x1+c2x2+...+cnxn=b,输出它的字典序最靠前的可行解
回溯法
回溯过程有两个维度,
xi本身
和xi的取值范围
注意剪枝
注意xi
取值从1
开始
#include <iostream>
#include <vector>
using namespace std;
vector<int> result;
bool backtracking(int Cs[], const int& n, const int& m, const int& target,
int start, int cur) {
if (cur > target) // 剪枝
return false;
else if (cur == target) // 找到解
return true;
else
for (int i = start; i < n; ++i) // 遍历xi
for (int j = 0; j < m; ++j) { // 遍历xi的取值
cur += Cs[i] * j;
result.push_back(j + 1);
if (backtracking(Cs, n, m, target, i + 1, cur)) // 递归
return true; // 有解,一路返回true
result.pop_back(); // 无解,继续回溯
cur -= Cs[i] * j;
}
return false;
}
int main() {
int n, m, b; // n:x维数 m:未知数x取值范围 b:结果以及系数c取值范围
while (cin >> n >> m >> b) {
result.clear();
int Cs[n]; // 系数数组
int offset = 0; // x全取1时的和,最小满足的解
for (int i = 0; i < n; ++i) {
cin >> Cs[i];
offset += Cs[i];
}
if (offset > b || offset * m < b) { // 无解情况
cout << -1 << endl;
continue;
}
// 可以整除时,即xi取值相同,直接输出,此时字典序最小
if (b % offset == 0) {
int clip = b / offset;
for (int i = 0; i < n; ++i) cout << clip << " ";
cout << endl;
continue;
}
// 开始递归
if (backtracking(Cs, n, m, b - offset, 0, 0)) {
// 结果长度不足时补1(xi最小为1)
while (result.size() < n) result.push_back(1);
for (auto it : result) cout << it << " ";
cout << endl;
} else
cout << -1 << endl;
}
}