OpenMP - std :: next_permutation

时间:2015-11-08 14:49:16

标签: c++ openmp std traveling-salesman

我正在尝试使用OpenMP并行化我自己的旅行商问题的C ++实现。

我有一个计算道路cost()和矢量[0,1,2,...,N]成本的函数,其中N是道路的节点数。

main(),我正在努力找到最好的道路:

do
{
    cost();
} while (std::next_permutation(permutation_base, permutation_base + operations_number));

我试图使用#pragma omp parallel来并行化该代码,但这只会让它更耗时。 有没有办法并行化该代码?

2 个答案:

答案 0 :(得分:4)

<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:weightSum="2"> <LinearLayout android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_weight="1" android:background="#192832"> </LinearLayout> <LinearLayout android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_gravity="center" android:layout_weight="1" android:background="#193222"> </LinearLayout> </LinearLayout> <ImageView android:id="@+id/yourImage" android:src="@drawable/yourImageSrc" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true"/> </RelativeLayout> 不会在不同的线程上自动划分计算。如果要分割计算,则需要另外使用#pragma omp parallel,否则孔计算多次完成,每个线程一次。例如,以下代码打印&#34; Hello World!&#34;我的笔记本电脑上有四次,因为它有4个核心。

#pragma omp for

如果你简单地写int main(int argc, char* argv[]){ #pragma omp parallel cout << "Hello World!\n"; } ,你的代码就会发生同样的事情。您的代码会被执行多次,每个线程执行一次。因此,您的计划不会更快。如果你想将工作分成线程(每个线程做不同的事情),你必须使用#pragma omp parallel之类的东西。

现在我们可以查看您的代码了。它不适合并行化。让我们看看为什么。您从数组#pragma omp parallel for开始计算成本。然后用permutation_base操纵permutation_base。在允许操作数组之前,您实际上必须等待完成的成本计算,否则成本计算将是错误的。所以整个事情不会在单独的线程上工作。

一种可能的解决方案是保留数组next_permutation的多个副本,并且每个可能的排列基础只运行所有排列的一部分。例如:

permutation_base

答案 1 :(得分:1)

绝对是最好的。

并行化这些排列问题的一个大问题是,为了很好地并行化,你需要“索引”成一个任意的排列。简而言之,您需要找到第k个排列。你可以利用一些很酷的数学属性,你会发现:

std::vector<int> kth_perm(long long k, std::vector<int> V) {
    long long int index;
    long long int next;
    std::vector<int> new_v;
    while(V.size()) {
        index = k / fact(V.size() - 1);
        new_v.push_back(V.at(index));
        next = k % fact(V.size() - 1);
        V.erase(V.begin() + index);
        k = next;
    }
    return new_v;
}

那么你的逻辑可能看起来像这样:

long long int start = (numperms*threadnum)/ numthreads;
long long int end = threadnum == numthreads-1 ? numperms : (numperms*(threadnum+1))/numthreads;

perm = kth_perm(start, perm); // perm is your list of permutations

for (int j = start; j < end; ++j){
    if (is_valid_tour(adj_list, perm, startingVertex, endingVertex)) {
        isValidTour=true;
        return perm;
    }
    std::next_permutation(perm.begin(),perm.end());
}

isValidTour = false;
return perm;

显然有很多代码,但是我发布的小代码可以捕获并行化的想法。你可以像这样想象“索引”:

|--------------------------------|
^        ^                   ^
t1      t2        ...        tn

找到第i个排列并让线程调用std::next_permutation,直到找到下一个线程的起点。

请注意,您需要在#pragma omp parallel

中包含包含底部代码的函数