HDU OJ -- Game of Connections(ACM Steps:2.3.7)

一、概述

1.问题描述

给出2n个数,从1开始把它们按顺时针方向构成一个圆。将圆内的2n个数字两两连线,连线之间不能相交,问可能的连线方式有几种?(1=

2.问题链接

HDU OJ -- Game of Connections(ACM Steps:2.3.7)

3.问题截图

如图1.1。

HDU OJ -- Game of Connections(ACM Steps:2.3.7)_第1张图片

图1.1  问题截图

二、算法思路

一开始没什么思路,将n取了几个值后,发现了其中的规律。

1.n=1

当n=1时,有2 x 1 = 2个数,两个数可以看成两个点,由于两点仅能组成一条线段,所以可能的连线方式为1种,这里设y(n)为问题规模为n时题目的解答,当n=1时,记y(1)=1。如图2.1所示。

HDU OJ -- Game of Connections(ACM Steps:2.3.7)_第2张图片

图2.1  n=1时的解答图示

2.n=2

当n=2时,有2 x 2 = 4个数,可能的连线方式如图2.2所示。

HDU OJ -- Game of Connections(ACM Steps:2.3.7)_第3张图片

图2.2  n=2时的解答图示

根据题意,无论哪种结果(即满足条件的连线方式),每个数字都会找到自己对应的数字组成线段,对于数字1也不例外,所以这里可以将问题这样求解:让数字1与剩余的数字分别做连线,并统计每种连线下可能的结果,它们的和即是问题最后的结果。当n=2时,除了1外还剩下3个数字,题目的求解转变为让1分别于3个数字做连线,然后分别对这三种情况求出结果,如图中的1),2),3)所示。

1)1与2连线

当1与2连线后,3和4处于孤立状态,并且他们在同一个区域,所以问题变为:2个数字有几种组成连线的方式,这恰是n=1时所描述的问题,如图中1)部分的红色圆圈所示,由于前面已将n=1时的结果计算出,这里可以得出结论:n=2,当1与2连线时,可能的连线方式有y(1) = 1种。

2)1与3连线

当1与3连线后,剩余的数字,即3和4将不可能构成满足题意的线段(即不相交的线段组合)。故当n=2,1与3连线时,可能的连线方式有0种。

3)1与4连线

1与4连线后,2和3处于孤立状态,并且处于同一区域,这是和情况1)完全相同,所以n=2,当1与4连线时,可能的连线方式有1种。

综上,n=2时,题目的最后结果,即y(2) = y(1) + y(1) = 2种。

从上面也可以得出结论:1与奇数数字连线时,将不具有满足题意的结果。因为连线后,相当于把圆分成了两个区域,而如果某个区域内有奇数个数字,那么必定有1个数字要与其他区域的数字相连,这样就一定会产生相交的连线。如n=2,当1与3连线后,分成了两个区域,一个区域含有数字2,一个区域含有数字4,它们要构成线段必定要与其他的线段产生交点。

 

3.n=3

n=3,有6个数字,可能的结果如图2.3所示。

HDU OJ -- Game of Connections(ACM Steps:2.3.7)_第4张图片

图2.3  n=3时的解答图示

如n=2所得出的结论所述,当n=3时,只需要计算数字1与偶数数字连线下的结果即可。

1)1与2连线

1与2连线后,剩余4个孤立数字,并且4个数字处于同一区域,问题变为:4个数字有几种组成连线的方式,这恰是n=2时所描述的问题,如图中1)部分的红色圆圈所示,n=2的结果已经计算过,所以这里有结论:n=3,1与2连线时,可能的连线方式有y(2) = 2种。

2)1与4连线

1与4连线后,剩余4个孤立数字,但是处于两个区域,其中2个数字在一个区域,另外2个数字在另一区域,每个区域都是n=1时所描述的问题,由于两个区域的连线方式可以自由组合,所以有结论当n=3,1与4连线后,可能的连线方式有y(1) x y(1) = 1 x 1 = 1种。

3)1与6连线

1与6连线后,剩余4个孤立数字,并且4个数字处于同一区域,这与1)描述一致,故可能的连线方式有2种。

综上,n=3时,y(3) = y(2) + y(1) x y(1) + y(2) = 2 + 1 x 1 + 2 = 5种。

 

4.n=4

n=4时,有8个数字,可能的结果如图2.4所示。

HDU OJ -- Game of Connections(ACM Steps:2.3.7)_第5张图片

图2.4  n=4时的解答图示

1)1与2连线

连线后,6个数字处于1个区域,这是n=3时所描述的问题,故可能的结果为y(3) = 5。

2)1与4连线

连线后,6个数字处于2个区域,其中2个在一个区域,这是n=1时问题描述的情形,另外4个在另一个区域,这是n=2时问题描述的情形,所以可能的结果为y(1) x y(2) = 1 x 2 = 2。

3)1与6连线

连线后,与2)描述的情景相同,故可能的结果为2种。

4)1与8连线

连线后,与1)描述的情景同,故结果为5种。

综上,y(4) = y(3) + y(1) x y(2) + y(2) x y(1) + y(3) = 5 + 1 x 2 + 1 x 2 + 5 = 14种。

 

综合上述n的四个取值对应的y(n),可以发现y(n)的计算具有一定的规律:

这里假设y(0) = 1

y(1) = 1

y(2) = y(1) x y(0) + y(0) x y(1)

y(3) = y(2) x y(0) + y(1) x y(1) + y(0) x y(2)

y(4) = y(3) x y(0) + y(2) x y(1) + y(1) x y(2) + y(0) x y(3)

...

y(n) = y(n-1) x y(0) + y(n-2) x y(1) + ... + y(0) x y(n-1)

三、算法实现

#include 
    #include 
    #include 
    using namespace std;
    class NumStr
    {
    public:
        string str;
        NumStr()=default;
        NumStr(string str):str(str){}
        bool operator==(NumStr& oprand)
        {
            if(str.size()!=oprand.str.size())
                return false;
            for(unsigned i=0;ilen2)
                return false;
            else if(len1=0;i--)
            {
                if(str[i]>oprand.str[i])
                    return false;
                else if (str[i]'9')
                {
                    carry=1;
                    tmp-=10;
                }
                else
                {
                    carry=0;
                }
                ret.str+=tmp;
            }
            if(str.size()>minLen)
            {
                for(unsigned i=minLen;i'9')
                    {
                        carry=1;
                        tmp-=10;
                    }
                    else
                    {
                        carry=0;
                    }
                    ret.str+=tmp;
                }
            }
            if(oprand.str.size()>minLen)
            {
                for(unsigned i=minLen;i'9')
                    {
                        carry=1;
                        tmp-=10;
                    }
                    else
                    {
                        carry=0;
                    }
                    ret.str+=tmp;
                }
            }
            if(carry)
                ret.str+='1';
            return ret;
        }
        NumStr operator*(unsigned char oprand)
        {
            NumStr ret;
            unsigned char carry=0;
            unsigned char tmp;
            for(unsigned i=0;i0)
                        tmpStr.str.insert(0,i,'0');
                    ret=ret+tmpStr;
                }
            }
            return ret;
        }
        void print()
        {
            for(int i=str.size()-1;i>=0;i--)
                cout<>n && n!=-1)
        {
            y[n].print();
            cout<

 

你可能感兴趣的:(算法,OJ)