切割多边形

Description

在一个凸n边形中,通过不相交于n边形内部的对角线,把n边形拆分成若干三角形。现在的任务是从键盘输入凸多边形的边数n,求不同剖分的方案数Cn。

Analysis

困难的一题。

不谈1000的数据量加上大整数会不会TLE,先分析一下转移方程。

不妨以点为突破口。显而易见,每个点要么被连接,要么不被连接。

  • 当不被连接时,其相邻两点一定连接,则n边形转化为n-1边形。
  • 当被连接时,可以与n-3个点相连,那么相连之后分割出i边形和n-i+2边形。为了防止重复,即连接第i个点时要保证不连接i+1~n-3,可以将n-i+2边形转化为n-i+1边形,即自动视为此点不与i+1~n-3个点相连。

动规方程:

dp[i]=dp[i-1]+dp[3]*dp[i-2]+...+dp[i-1]*dp[2]

因为dp[2]=1,所以又可以写成

dp[i]=dp[2]*dp[i-1]+...+dp[i-1]*dp[2]

状态转移复杂度为O(n^2),再算上高精度处理O(1000),TLE。

那么,怎么通过O(n)乃至更小的复杂度转移状态呢。我不知道,所以看了hj解题报告,了解了Catlan Queue。

不进行证明。

Code

#include <bits/stdc++.h>

struct bigint{
    int len,num[5010];
    bigint operator = (int eq){
        len=0;
        memset(num,0,sizeof(num));
        while(eq){
            num[len++]=eq%10;
            eq/=10;
        }
        return *this;
    }
    bigint operator * (bigint mt){
        bigint ans;
        ans.len=len+mt.len-1;
        memset(ans.num,0,sizeof(ans.num));
        for(int i=0;i<len;i++)
            for(int j=0;j<mt.len;j++)
                ans.num[i+j]+=num[i]*mt.num[j];
        int add=0;
        for(int i=0;i<ans.len;i++){
            ans.num[i]+=add;
            add=ans.num[i]/10;
            ans.num[i]%=10;
        }
        while(add){
            ans.num[ans.len++]=add%10;
            add/=10;
        }
        return ans;
    }
    bigint operator * (int mt){
        bigint bigmt;
        bigmt=mt;
        return *this*bigmt;
    }
    bigint operator *= (int mt){
        return *this=*this*mt;
    }
    bigint operator / (int dv){
        bigint ans;
        ans.len=len;
        memset(ans.num,0,sizeof(ans.num));
        int bc=0;
        for(int i=len-1;i>=0;i--){
            bc=bc*10+num[i];
            if(bc>=dv)ans.num[i]=bc/dv,bc%=dv;
        }
        while(ans.len-1&&!ans.num[ans.len-1])ans.len--;
        return ans;
    }
    bigint operator /= (int dv){
        return *this=*this/dv;
    }
    friend std::ostream& operator << (std::ostream& out,bigint ans){
        for(int i=ans.len-1;i+1;i--)
            out<<ans.num[i];
        return out;
    }
};

int n;

bigint Catlan(int x){
    bigint ans;
    ans=x+2;
    for(int i=x+3;i<=x*2;i++)
        ans*=i;
    for(int i=2;i<=x;i++)
        ans/=i;
    return ans;
}

int main(){
    freopen("test.in","r",stdin);
    freopen("test.out","w",stdout);
    std::cin>>n;
    if(n==1)std::cout<<0<<std::endl;
    else if(n<4)std::cout<<1<<std::endl;
    else std::cout<<Catlan(n-2)<<std::endl;
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/qswx/p/9492564.html