新生选拔二 - Make Triangle SPOJ - TRNGL (卡特兰数)

题目链接 Make Triangle


题意

给你一个N边型,用(N-3)条对角线来把它切割成(N-2)个三角形,其中对角线不能相交。输出一共有几种切法,并对100007取模。


思路

这种一看就是要找规律的,比如把一个N边形切掉一个角成N-1和一个三边形,但是这个方法我试了一个小时,并没有什么结果,因为其重复的情况实在是太多了。最后的十分钟我终于有了思路,然而,时间不够了。。。。。。来讲一下方法。每次都以一条边为基础,然后枚举上方的顶点,组成一个个的三角形,通过这个三角形来对原来的N边型进行划分,这样的划分是不会出现重复的。据说这是卡特兰数,新技能学学习中。

具体解释

固定一条边,枚举一个点与这条边构成一个三角形,进而把这个大的凸多边形分成了两个较小的凸多边形和该三角形,设左边是一个i边形,那么右边就是一个n+1-i边形,dp[n]=Sum( dp[i]*dp[n+1-i] ),2<=i<=n-1 (i=2和i=n-1表示的是这条边与其相邻的一个顶点构成了一个三角形,那么这个大的凸多边形其实是变成了一个小的凸多边形和该三角形,为方便起见可以令dp[2]=1),O(n^2)预处理dp数组,每次查询O(1)输出即可 。


代码一

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;

ll sum[1007];

int main()
{
    ios::sync_with_stdio(false);
    sum[1] = 1;
    sum[2] = 2;

    for (ll i = 3;i <= 1000;i ++){
        sum[i] = (sum[i-1]*2) ;
        sum[i] %= 100007;
        for (ll j = 1;j <= i-2;j ++){
            sum[i] += sum[j]*sum[i-j-1];
            sum[i] %= 100007;
        }
        sum[i] %= 100007;
    }

    ll T;
    cin >> T;
    while (T --){
        ll n;
        cin >> n;
        cout << sum[n-2] << endl;
    }
}

代码二

// 一个提交时间是我1/9的代码
#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
const ll MOD = (ll)100007;

ll dp[1007];

void init()
{
    dp[2] = dp[3] = 1;
    for(int i = 4;i <= 1000;i ++){
        dp[i] = 0;
        for(int j = 2;j < i;j ++)dp[i] = (dp[i] + dp[j]*dp[i+1-j]%MOD)%MOD;
    }
}
int main()
{
    init();
    int T,n;
    scanf("%d",&T);
    while(T --){
        scanf("%d",&n);
        printf("%lld\n",dp[n]);
    }
    return 0;
}
阅读更多
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_40513946/article/details/79958972
个人分类: 规律,静心
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭
关闭