按字典顺序排列的给定锯齿形排列的最小排列

时间:2012-07-26 07:57:42

标签: algorithm complexity-theory permutation

这是我正在研究的一个问题。我尝试了很多但不能比O(n ^ 2)更好。

 You are given a set of numbers from 1 to K.And you need to find 
 the minimum possible lexicographical set of numbers with following
 constraints.You are given K numbers of sets of Yes 'Y' or NO 'N' from
 1 to K.And the swap is only possible if the value is 'Y'.Sorry for my
 poor English.Hope this example helps get you the problem. 
 NOTE: 1 < K < 101
 Take an example:
 K=3
Given set of numbers is :  3 1 2
                           N N Y
                           N N N
                           Y N N
     Here you can swap j and i+2 element since the value is Y.

Thus,the output would be   2 1 3

有人可能会建议我采用比这种方法更好的方法吗?

感谢。

2 个答案:

答案 0 :(得分:2)

只考虑可交换元素给出的矩阵。我认为假设如果arr [i] [j]代表表示我是否可以用j交换的元素,则可以公平地说明

arr[i][j] = arr[j][i] ; for all i, j pairs

此外,如果 i 可以与 j 交换, j 可以与 k 交换,那么可以通过 j k 交换 i

使用这些信息,我们可以看到,如果我们可以构造一组索引,使得对于集合中的每个元素 i ,至少存在一个元素 j 它可以交换,然后我们可以简单地按排序顺序排列这些指数的值,这将是这些指数可能的按字典顺序排列的最小排列。如果我们继续考虑所有这些集合,那么我们最终将采用按字典顺序排列的最小排列。

另一种查看问题的方法(而不是将它们视为不相交集的集合)是将其视为图形问题。如果每个索引是一个节点,并且如果它们可以交换,则它们是两个索引之间的边缘,那么我们需要找到不同的强连接组件(SCC)并对每个这样的组件中的元素进行排序。这很明显,如果你注意到强连接组件中的任何索引都不能与该组件之外的位置交换,因此我们可以自己对每个SCC进行排序并获得所需的结果。

此问题也在CodeSprint3中提出,我对此的解决方案是: -

#include <iostream>
#include <algorithm>
#include <set>
#include <queue>
#include <cstring>


using namespace std;

void sccSetInsertions (set<int>& indexSet, set<int>& valSet, const int& i, const int& val)
{
    indexSet.insert (i);
    valSet.insert(val);
}

void checkSCCMembers(const int& i, const int& k, int *arr, int *swaps, queue<int>& bfsQ,
                     set<int>& sccVals, set<int>& sccIndices, int *considered)
{
    for (int j = 0; j < k; j++)
    {
        if (swaps[j] == 1)
        {
            if (considered[j] == 0)
            {
                bfsQ.push(j);
                sccSetInsertions(sccIndices, sccVals, j, arr[j]);
                considered[j] = 1;
            }           
        }
    }
}

int main (void)
{
    int k, i, j;    
    cin >> k;   
    int arr[k];
    int swaps[k][k];

    for(i = 0; i < k; i++)
    {
        cin >> arr[i];
    }

    char c;    
    for(i = 0; i < k; i++)
    {
        for (j = 0; j < k; j++)
        {
            cin >> c; 
            swaps[i][j] = (c == 'Y');
        }   
    }


    set<int> sccIndices, sccVals;
    queue<int> bfsQ;        
    int considered[k], tmp;

    bzero (considered, sizeof(int) * k);

    for (i = 0; i < k; i++)
    {   
        if (considered[i] == 1)
            continue;
        else
        {

            sccSetInsertions(sccIndices, sccVals, i, arr[i]);
            considered[i] = 1;            
        }
        checkSCCMembers (i, k, arr, swaps[i], bfsQ, sccVals, sccIndices, considered);
        while (bfsQ.size() > 0)
        {
            tmp = bfsQ.front();
            bfsQ.pop();            
            checkSCCMembers(tmp, k, arr, swaps[tmp], bfsQ, sccVals, sccIndices, considered);
        }

        set<int>::iterator itVal = sccVals.begin(), itIndex = sccIndices.begin();
        for(; itIndex != sccIndices.end(); itIndex++, itVal++)
        {
            arr[*itIndex] = *itVal;        
        }
        sccIndices.clear();
        sccVals.clear();
    }

    for (i = 0; i < k; i++)
    {
        cout << arr[i];
        if (i != k - 1)
            cout << " ";
    }
    cout << endl;

    return 0;
}

答案 1 :(得分:1)

您可以使用任何排序算法。你只需要约束你的掉期。因此,您可以使用QuickSort,HeapSort等以O(nlgn)复杂度来交换约束。