多点两两连线问题

问题描述
  • 如下图,给定偶数个点,两两之间连线,规则为:

    1. 每个点仅能与另外一个点连接,如图:不准有1与3类似的连接
    2. 不能有剩余的点未与其他点连接。要求输入偶数个点,输出有多少中连接方式?

图片描述

问题分解
  1. 当有两个点时:只有1-2连接的情况
  2. 当有四个点时:会有1-2、3-4与1-4、2-3连接的情况,不能出现1-3这种交叉连接的情况
  3. 当有六个点时:

    • 首先固定点1,按照规则,能与1连接的点分别为:2、4、6,从以上三步总结下来,能与1点连接的点都是编号为偶数的节点
    • 假设1、2连接,那剩下的就是3、4、5、6节点,即固定1和2两个点,把6个点分隔成两个点(1, 2)和另外四个点(3, 4, 5, 6)的子问题
    • 假设1、4连接,那剩下的就是(2, 3)、(5, 6)节点连接的问题
  4. 问题分解到这里,我们便能想到:这是一个把复杂问题分解成子问题的需求,应用动态规划即可,动态规划的关键点在于找到子问题的解如何组合才能得到最终的结果
  5. 有了上述的思路,那接下来的分析便是要找到分解复杂问题的公式,分解到6个点的时候,可以得出一个公式:f(6) = 2f(4)f(2) + f(2)*f(2) ,即:步骤3的分析
  6. 从F部推到出的公式显然还不能得到解决,因为还不能用其解决8个、10个点的问题,那继续分析8个点的场景:

    • 固定点1,1能和2、4、6、8连接:1和2连接将问题分解为(1, 2)、(3, 4, 5, 6, 7, 8)连接的问题
    • 1和4连接,将问题分解为(1, 4)、(2, 3)、(5, 6, 7, 8)连接的问题
    • 1和6连接,将问题分解为(1, 6)、(2, 3, 4, 5)、(7, 8)的连接
    • 1和8连接,将问题分解为:(1, 8)、(2, 3, 4, 5, 6, 7)的连接
    • 那总结公式为:f(8) = 2f(6)f(2) + f(2)f(4) + f(4)f(2)
  7. 至此,依据以上的判断,可以总结出的规律为:

    • 给定N个点,当固定两个点时,剩余的N-2个点可以被分解成:固定部分2 f(N-2)f(2)以及子问题X个点与Y个点的连接,其中X+Y=N-2,X,Y < N-2
    • 例如若N为10,则X、Y可取为:2&6、4&4、6&2,
    • 推导出最终公式为:f(n)=f(2m)=2f(2m-2)f(2) + f(2i)f(2m-2i-2) + ... f(2i)f(2), i的取值范围是[1,m-2]
程序实现
#include <iostream>

uint32_t ChoicesofSpotConnection(int spot_num) {
    int* choices = new int[spot_num + 1];
    choices[0] = 0;
    choices[2] = 1;
    choices[4] = 2;
    choices[6] = 2 * choices[4] + choices[2] * choices[2];

    uint32_t count_time = spot_num / 2;
    for (uint32_t m = 4; m <= count_time; ++m) {
        choices[2 * m] = 2 * choices[2 * m - 2];
        for (uint32_t i = 1; i <= (m - 2); ++i) {
            choices[2 * m] += choices[2 * i] * choices[2 * m - 2 * i - 2];
        }
        std::cout << "2*m: " << 2 * m << ", choices: " << choices[2 * m] << std::endl;
    }
    return choices[spot_num];
}

int main(int argc, char* argv[]) {
    int rtn = ChoicesofSpotConnection(12);
    std::cout << "choices:" << rtn << std::endl;
    return 0;
}
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值