圆上没有交叉的和弦

时间:2015-09-07 09:58:13

标签: algorithm math geometry chord-diagram

我正在尝试执行该任务。我们在圆上有2 * n个点。所以我们可以在它们之间创建n个和弦。打印所有绘制n而不是交叉和弦的方法。

例如:如果n = 6.我们可以绘制(1-> 2 3-> 4 5-> 6),(1-> 4,2-> 3,5-> 6 ),(1-> 6,2-> 3,4-> 5),(1-> 6,2-> 5,3->)

我通过创建一个来自1->的和弦来开发递归算法。 2,4,6,并产生2个剩余间隔的答案。但我知道有更有效的非递归方式。可以通过实现NextSeq函数。

有没有人有任何想法?

UPD:我确实缓存了中间结果,但我真正想要的是找到GenerateNextSeq()函数,它可以按先前生成下一个序列,因此生成所有这样的组合

这是我的代码

struct SimpleHash {
    size_t operator()(const std::pair<int, int>& p) const {
        return p.first ^ p.second;
    }
};

struct Chord {
    int p1, p2;
    Chord(int x, int y) : p1(x), p2(y) {};
};

void MergeResults(const vector<vector<Chord>>& res1, const vector<vector<Chord>>& res2, vector<vector<Chord>>& res) {
    res.clear();
    if (res2.empty()) {
        res = res1;
        return;
    }


    for (int i = 0; i < res1.size(); i++) {
        for (int k = 0; k < res2.size(); k++) {
            vector<Chord> cur;

            for (int j = 0; j < res1[i].size(); j++) {
                cur.push_back(res1[i][j]);
            }

            for (int j = 0; j < res2[k].size(); j++) {
                cur.push_back(res2[k][j]);
            }
            res.emplace_back(cur);

        }

    }
}

int rec = 0;
int cached = 0;

void allChordsH(vector<vector<Chord>>& res, int st, int end, unordered_map<pair<int, int>, vector<vector<Chord>>, SimpleHash>& cach) {
    if (st >= end)
        return;

    rec++;

    if (cach.count( {st, end} )) {
        cached++;
        res = cach[{st, end}];
        return;
    }

    vector<vector<Chord>> res1, res2, res3, curRes;
    for (int i = st+1; i <=end; i += 2) {
        res1 = {{Chord(st, i)}};
        allChordsH(res2, st+1, i-1, cach);
        allChordsH(res3, i+1, end, cach);


        MergeResults(res1, res2, curRes);
        MergeResults(curRes, res3, res1);

        for (auto i = 0; i < res1.size(); i++) {
            res.push_back(res1[i]);
        }

        cach[{st, end}] = res1;

        res1.clear(); res2.clear(); res3.clear(); curRes.clear();
    }
}

void allChords(vector<vector<Chord>>& res, int n) {
    res.clear();

    unordered_map<pair<int, int>, vector<vector<Chord>>, SimpleHash> cach; // intrval => result

    allChordsH(res, 1, n, cach);
    return;
} 

1 个答案:

答案 0 :(得分:0)

使用动态编程。也就是说,缓存部分结果。

基本上,从1和弦开始,计算所有答案并将其添加到缓存中。 然后取2个和弦,尽可能使用缓存计算所有答案。 等

递归方式是O(n!)(至少n !,我对复杂度计算不好)。

这种方式是每步和n步的n / 2-1操作,因此O(n ^ 2),这要好得多。但是,此解决方案依赖于内存,因为它必须保留缓存中的所有组合。 15和弦很容易使用1GB内存(Java解决方案)。

示例解决方案: https://ideone.com/g81zP9

在~306ms内完成12个和弦计算。 给定1GB的RAM,它可以在~8秒内计算15个和弦。

缓存以特定格式保存以优化性能:数组中保存的数字表示链接的数量。例如[1,0,3,1,0,0]表示:

1  0  3  1  0  0
|--|  |  |--|  |
      |--------|

您可以在单独的步骤中将其转换为您想要的任何格式。