我的作业存在回溯问题,由于程序效率低下,我只能得到80/100分。问题的陈述如下:
给出n个自然数(n为偶数)。 n个数字是成对的,对于每个对,您都可以找到对中两个元素之间除法的余数,并将所有余数求和。找到该总和的最小值。2 <= n <= 18并且所有n个自然数都是<= 1000
示例:
n = 4,这4个数字是:{6,5,3,4}
结果为1。由于6与3配对,而5与4配对,所以余数的最小和为1。所以我们有{6,3}和{5,4}对。 6%3 == 0,所以第一对的余数为0。5%4 == 1,因此第二对的余数为1。0+ 1 = 1是最小的可能和。没有其他的元素对给出较小的余数和。
所以我尝试过的(因为这是一个回溯问题)是生成所有可能的对,找到余数并选择最小的对。但是我的解决方案效率不够高,只能得到80/100分。这是代码:
#include <iostream>
#include <climits>
using namespace std;
int n, a[20], v[20], first[20], second[20], suma_min=INT_MAX;
bool solution() {
int i;
for (i=1; i<=n; i++) {
if (a[i] != -1) {
return false;
}
}
return true;
}
void find_sum() {
int i, curr_sum=0;
for (i=1; i<=n/2; i++) {
curr_sum = curr_sum + (first[i] % second[i]);
}
if (curr_sum < suma_min) {
suma_min = curr_sum;
}
}
void backtrack(int k,int stage) {
int i;
for (i=1; i<=n; i++) {
if (a[i] != -1) {
if (stage == 1) {
first[k] = a[i];
a[i] = -1;
if (solution()) {
find_sum();
}
else {
backtrack(k, stage+1);
}
a[i] = v[i];
}
else {
second[k] = a[i];
a[i] = -1;
if (solution()) {
find_sum();
}
else {
backtrack(k+1, stage-1);
}
a[i] = v[i];
}
}
}
}
int main()
{
int i;
cin >> n;
for (i=1; i<=n; i++) {
cin >> v[i];
a[i] = v[i];
}
backtrack(1,1);
cout << suma_min;
return 0;
}
有没有办法更快地做到这一点?是否有一种算法可以将数组的所有元素2 2配对?非常感谢您的帮助。