如何使用回溯对向量的所有元素进行配对

时间:2019-04-11 18:34:49

标签: c++ backtracking

我的作业存在回溯问题,由于程序效率低下,我只能得到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配对?非常感谢您的帮助。

0 个答案:

没有答案