`
bobten2008
  • 浏览: 11150 次
  • 性别: Icon_minigender_1
  • 来自: 北京
最近访客 更多访客>>
社区版块
存档分类
最新评论

POJ 2084 Game of Connections

阅读更多

Game of Connections
Time Limit: 1000MS Memory Limit: 30000K
Total Submissions: 4839 Accepted: 2515

Description

This is a small but ancient game. You are supposed to write down the numbers 1, 2, 3, . . . , 2n - 1, 2n consecutively in clockwise order on the ground to form a circle, and then, to draw some straight line segments to connect them into number pairs. Every number must be connected to exactly one another. 
And, no two segments are allowed to intersect. 
It's still a simple game, isn't it? But after you've written down the 2n numbers, can you tell me in how many different ways can you connect the numbers into pairs? Life is harder, right?

Input

Each line of the input file will be a single positive number n, except the last line, which is a number -1. 
You may assume that 1 <= n <= 100.

Output

For each n, print in a single line the number of ways to connect the 2n numbers into pairs.

Sample Input

2
3
-1

Sample Output

2
5

Source


/*
卡特兰数 + 大数运算,一开始自己推公式得到的结论是:
f(2 * n) = f(0) * f(2 * n - 2) + f(2) * f(2 * n - 4) + f(4) * f(2 * n - 6) + ... + f(2 * n - 2) * f(0);
然后纯粹基于递推来算, 发现结果是对的,但是速度太慢,超时了。后来想了想,这不就是卡特兰数吗?呵呵,问题解决了
F(n) = F(0) * F(n - 1) + F(1) * F(n - 2) + ... + F(n - 1) * F(0) = C(2 * n, n) / (n + 1), F(0) = 1
代码很长,大部分是自己写的大数运算工具模板, 哈哈
*/
#include <iostream>
#include <string>
#define BIGINTEGER_LEN_TYPE int
#define MAX_N 201
using namespace std;

string num[MAX_N];
string cval[MAX_N][MAX_N];

//大数加法
string bigIntegerAdd(const string left, const string right)
{
    BIGINTEGER_LEN_TYPE lenl = static_cast<BIGINTEGER_LEN_TYPE>(left.size());
    BIGINTEGER_LEN_TYPE lenr = static_cast<BIGINTEGER_LEN_TYPE>(right.size());
    std::string res = "";
    
    //get the minimum length of the two string
    BIGINTEGER_LEN_TYPE minLen = (lenl <= lenr) ? lenl : lenr;
    BIGINTEGER_LEN_TYPE maxLen = (lenl <= lenr) ? lenr : lenl;
    std::string longerStr = (lenl <= lenr) ? right : left;
    
    int residue = 0, sum = 0, quotient = 0;
    //add operation, first part
    BIGINTEGER_LEN_TYPE pos1;
    for(pos1 = 0; pos1 <= minLen - 1; pos1++)
    {
        sum = (left[pos1] - '0') + (right[pos1] - '0') + quotient;
        quotient = sum / 10;
        residue = sum % 10;
        res += residue + '0';
    }
    //add operation, second part
    for(BIGINTEGER_LEN_TYPE pos2 = pos1; pos2 <= maxLen - 1; pos2 ++)
    {
        sum = (longerStr[pos2] - '0') + quotient;
        quotient = sum / 10;
        residue = sum % 10;
        res += residue + '0';
    }
    //add the extra carry
    while(quotient != 0)
    {
        residue = quotient % 10;
        quotient = quotient / 10;
        res += residue + '0';
    }
    //std::cout<<"res size:"<<res.length()<<std::endl;
    return res;
}

//大数乘法
string bigIntegerMult(const string left, const string right)
{
    BIGINTEGER_LEN_TYPE minLen = static_cast<BIGINTEGER_LEN_TYPE>(left.length());
    BIGINTEGER_LEN_TYPE maxLen = static_cast<BIGINTEGER_LEN_TYPE>(right.length());
    std::string longerStr = "";
    std::string shorterStr = "";
    std::string res = "";
    //get the longer and short strings and corresponded length
    if(left.length() <= right.length())
    {
        minLen = static_cast<BIGINTEGER_LEN_TYPE>(left.length());
        maxLen = static_cast<BIGINTEGER_LEN_TYPE>(right.length());
        shorterStr = left;
        longerStr = right;
    }
    else
    {
        minLen = static_cast<BIGINTEGER_LEN_TYPE>(right.length());
        maxLen = static_cast<BIGINTEGER_LEN_TYPE>(left.length());
        shorterStr = right;
        longerStr = left;
    }
    BIGINTEGER_LEN_TYPE pos1 = 0;
    BIGINTEGER_LEN_TYPE pos2 = 0;
    //start from the first digit of the shorter string
    for(pos1 = 0; pos1 <= minLen - 1; pos1++)
    {
        //multiply each digit of the longer string
        int residue = 0, product = 0, quotient = 0;
        BIGINTEGER_LEN_TYPE curPos = 0;
        for(pos2 = 0; pos2 <= maxLen - 1; pos2++)
        {
            curPos = pos1 + pos2;
            //new space
            if(res.length() == 0 || curPos > int(res.length() - 1))
            {
                product = (shorterStr[pos1] - '0') * (longerStr[pos2] - '0') + quotient;
                quotient = product / 10;
                residue = product % 10;
                res += residue + '0';
            }
            //space already exists, just add the original value to product
            else
            {
                product = (shorterStr[pos1] - '0') * (longerStr[pos2] - '0') + quotient + (res[curPos] - '0');
                quotient = product / 10;
                residue = product % 10;
                res[curPos] = residue + '0'; 
            }
        }
        //process the extra quotient
        //start position
        curPos = maxLen + pos1;
        while(quotient != 0)
        {
            if(res.length() == 0 || curPos > int(res.length() - 1))
            {
                residue = quotient % 10;
                quotient = quotient / 10;
                res += residue + '0';
            }
            else
            {
                quotient = quotient + (res[curPos] - '0');
                residue = quotient % 10;
                quotient = quotient / 10;
                res[curPos] = residue + '0';
            }
            curPos++;
        }
    }
    //std::cout<<res.length()<<std::endl;
    return res;
    
}

//对字符串str进行翻转
string getReverse(const string str)
{
    std::string revStr = "";
    BIGINTEGER_LEN_TYPE pos = static_cast<BIGINTEGER_LEN_TYPE>(str.length()) - 1;
    for(; pos >= 0; pos--)
        revStr += str[pos];
    return revStr;
}

//比较两个大数的大小
int bigIntegerCmp(const string left, const string right)
{
    BIGINTEGER_LEN_TYPE lenl = static_cast<BIGINTEGER_LEN_TYPE>(left.length());
    BIGINTEGER_LEN_TYPE lenr = static_cast<BIGINTEGER_LEN_TYPE>(right.length());
    if(lenl < lenr)
        return -1;
    else if(lenl > lenr)
        return 1;
    return strcmp(getReverse(left).c_str(), getReverse(right).c_str());
}

//大数减法
string bigIntegerSub(const string left, const string right)
{
    std::string biggerStr = "";
    std::string smallerStr = "";
    std::string res = "";
    BIGINTEGER_LEN_TYPE minLen = 0;
    BIGINTEGER_LEN_TYPE maxLen = 0;
    
    //get the bigger integer and smaller integer
    int cmpRes = bigIntegerCmp(left, right);
    if(cmpRes == -1 || cmpRes == 0)
    {
        smallerStr = left;
        biggerStr = right;
    }
    else
    {
        smallerStr = right;
        biggerStr = left;
    }
    //get related size
    minLen = static_cast<BIGINTEGER_LEN_TYPE>(smallerStr.length());
    maxLen = static_cast<BIGINTEGER_LEN_TYPE>(biggerStr.length());
    
    int extra = 0, temp = 0, subRes = 0;
    //subtraction operation, first part
    BIGINTEGER_LEN_TYPE pos1;
    for(pos1 = 0; pos1 <= minLen - 1; pos1++)
    {
        int curL = biggerStr[pos1] - '0';
        int curR = smallerStr[pos1] - '0';
        temp = 0;
        while((subRes = (curL - curR + 10 * temp - extra)) < 0)
            temp++;
        res += subRes + '0';
        extra = temp;
    }
    //subtraction operation, second part
    for(BIGINTEGER_LEN_TYPE pos2 = pos1; pos2 <= maxLen - 1; pos2 ++)
    {
        int curL = biggerStr[pos2] - '0';
        temp = 0;
        while((subRes = (curL + 10 * temp - extra)) < 0)
            temp++;
        res += subRes + '0';
        extra = temp;
    }
    //remove the zero at head
    while(res[res.length() - 1] == '0' && res.length() >= 2)
        res = res.substr(0, res.length() - 1);
    
    //std::cout<<"res size:"<<res.length()<<std::endl;
    return res;
}

//把整数转换为字符串
string getStr(int a)
{
    string res = "";
    if(a == 0) return "0";
    else
    {
        while(a)
        {
            res = char(a % 10 + '0') + res;
            a = a / 10;
        }
    }
    return res;
}

//大数除法
void bigIntegerDiv(const std::string left, const std::string right, std::string & quotient, std::string & residual)
{
    int type = bigIntegerCmp(left, right);
    //left < right
    if(type == -1)
    {
        quotient = "0";
        residual = left;
        return;
    }
    //left = right
    else if(type == 0)
    {
        quotient = "1";
        residual = "0";
        return;
    }
    //left > right
    //initialize the related data 
    quotient = "";
    residual = "";
    std::string dividend = left;
    std::string divisor = right; 
    BIGINTEGER_LEN_TYPE lenDend = static_cast<BIGINTEGER_LEN_TYPE>(left.length());
    BIGINTEGER_LEN_TYPE lenDsor = static_cast<BIGINTEGER_LEN_TYPE>(right.length());
    
    std::string temp = "";
    std::string curStr = "";
    std::string tryStr = "";
    BIGINTEGER_LEN_TYPE curPos = 0;
    int choice = 0;
    bool visitedFirst = false;
    //start from the head of the dividend
    for(curPos = lenDend - 1; curPos >= 0; curPos--)
    {
        curStr = dividend[curPos] + curStr;
        //curStr > divisor, can be processed
        if(bigIntegerCmp(curStr, divisor) >= 0)
        {
            //try the quotient from 1 to 10 until the result of choice * divisor is the biggest less than curStr
            for(choice = 1; choice <= 10; choice++)
            {
                temp = "";
                temp += char(choice + '0');
                tryStr = bigIntegerMult(divisor, temp);
                if(bigIntegerCmp(tryStr, curStr) > 0)
                {
                    choice--;
                    break;
                }
            }
            //right now, choice is just the current quotient and should be appended ahead to quotient
            quotient = char(choice + '0') + quotient;
            temp = "";
            temp += char(choice + '0');
            //update curStr
            curStr = bigIntegerSub(curStr, bigIntegerMult(divisor, temp));
            if(curPos == 0)
                residual = curStr;
            //set visitedFirst, visitedFirst is used to prevent producing '0' quotient
            visitedFirst = true;
        }
        //curStr is not enough to be divided by divisor, so the current quotient is '0' and should be appended to 'quotient'
        else if(visitedFirst)
            quotient = '0' + quotient;
        if(curPos == 0)
        {
            residual = curStr;
            break;
        }
        if(curStr == "0")
            curStr = "";
    }
    residual = curStr;
    return;
}

string getCval(int p, int q)
{
    if(p == q || q == 0) return "1";
    if(q == 1) return getReverse(getStr(p));
    
    if(cval[p][q] != "0") return cval[p][q];
    
    return cval[p][q] = bigIntegerAdd(getCval(p - 1, q - 1), getCval(p - 1, q));
} 

//计算k的卡特兰数,下标从0开始
string solve1(int k)
{
    if(num[k] != "0") return num[k];
    string quotient, residual;

    bigIntegerDiv(getCval(2 * k, k), getReverse(getStr(k + 1)), quotient, residual);
    
    return quotient;
}

int main()
{
    int i, j, p;
    for(i = 1; i < MAX_N; i++) 
    {
        num[i] = "0";
        for(j = 1; j < MAX_N; j++)
            cval[i][j] = "0"; 
    }
    num[1] = "1";
    while(scanf("%I64d", &p) && p != -1)
        cout<<getReverse(solve1(p))<<endl;
    return 0;
}
 

 

分享到:
评论

相关推荐

    POJ1027-The Same Game

    【标题】"POJ1027 - The Same Game"是一个经典的编程竞赛题目,源自北京大学的在线编程平台POJ(Problem Online Judge)。该题目主要考察的是动态规划和矩阵链乘法的知识,要求参赛者编写程序解决一个具有策略性的...

    POJ1753-Flip Game

    北京大学在线编程平台POJ(Problemset Online Judge)中的题目POJ1753——“Flip Game”,就是一个很好的锻炼逻辑思维和算法设计的实例。本篇文章将对这个问题进行深入解析,并提供两种不同的解决方案:一种基于广度...

    poj 1353 Color Change of Go Game Pieces.md

    poj 1353 Color Change of Go Game Pieces.md

    poj 2771 Guardian of Decency.md

    poj 2771 Guardian of Decency.md

    poj题目分类...

    * 2084 Game of Connections * 1906 Three powers * 1835 宇航员 * 1799 Yeehaa! * 1607 Deck * 1244 Slots of Fun * 1269 Intersecting Lines * 1299 Polar Explorer * 1183 反正切函数的应用 POJ 题目分类可以...

    poj 2903 Joy of Mobile Routing.md

    poj 2903 Joy of Mobile Routing.md

    poj 3174 Alignment of the Planets.md

    poj 3174 Alignment of the Planets.md

    POJ 3083 Children of the Candy Corn解题报告

    ### POJ 3083 Children of the Candy Corn 解题报告 #### Description 题目描述了一个典型的迷宫问题:在一个玉米地迷宫中,游客需要找到从入口到出口的路径。题目给出了一个常见的策略:选择左墙或右墙并沿着它...

    POJ2151-Check the difficulty of problems

    标题“POJ2151-Check the difficulty of problems”是指一个编程竞赛题目,来源于北京大学的在线判题系统POJ(PKU Online Judge)。这个题目要求参赛者编写程序来评估问题的难度。描述中的“解题报告+AC代码”表明...

    POJ2109-Power of Cryptography

    《POJ2109-Power of Cryptography:解题报告与AC代码解析》 在计算机科学领域,算法和编程竞赛是检验和提升编程技能的重要途径。POJ(Problem Set of Peking University)是由北京大学主办的一个在线编程竞赛平台,...

    POJ2942-Knights of the Round Table【Tarjan算法】

    POJ2942-Knights of the Round Table 【Tarjan算法】 解题报告+AC代码 http://hi.csdn.net/!s/F3L8HO ================================== 我的POJ所有解题报告:...

    POJ.rar_poj java_poj1048

    【描述】"POJ1048,加强版的约瑟夫问题 难度中等" 提示我们,这个问题是编程竞赛POJ(Problemset of JiaoShi University)中的一个挑战,难度适中。约瑟夫问题是经典的计算机科学问题,它源自一个古代犹太人的传说。...

    POJ3253-POJ3253-Fence Repair【STL优先队列】

    标题“POJ3253-POJ3253-Fence Repair【STL优先队列】”指的是一个在线编程竞赛题目,源自北京大学的在线判题系统POJ(Problem Online Judge)。该题目要求参赛者使用C++编程语言解决特定的问题,并且在解决方案中...

    poj 3901 The Computer Game.md

    poj 3901 The Computer Game.md

    POJ算法题目分类

    * 图的深度优先遍历和广度优先遍历:图的深度优先遍历和广度优先遍历是指遍历图的两种方式,如 poj1860、poj3259、poj1062、poj2253、poj1125、poj2240。 * 最短路径算法:最短路径算法是指计算图中两点之间的最短...

    POJ2739-Sum of Consecutive Prime Numbers

    【描述】该题目来源于北京大学的在线编程平台POJ(Problem Online Judge),编号为2739,名为"Sum of Consecutive Prime Numbers"。这是一道关于算法与数论的编程题目,要求参赛者编写程序来计算连续的素数之和。...

    POJ1010-STAMPS

    【标题】"POJ1010-STAMPS"是一个编程题目,来源于北京大学的在线判题系统POJ(Problem Set of Peking University),这是一处训练程序员算法技能和编程能力的平台。该题目旨在考察参赛者对动态规划或贪心算法的理解...

    POJ1159-Palindrome

    【标题】"POJ1159-Palindrome" 是北京大学在线编程平台POJ上的一道编程题目。这道题目主要考察的是字符串处理和回文判断的知识点。 【描述】"北大POJ1159-Palindrome 解题报告+AC代码" 暗示了解决这道问题的方法和...

    ACM-POJ 算法训练指南

    1. **状态转移方程**:设计复杂的动态规划状态转移方程(poj1191, poj1054, poj3280, poj2029, poj2948, poj1925, poj3034)。 2. **记忆化搜索**:结合动态规划和递归搜索(POJ3254, poj2411, poj1185)。 3. **...

    POJ2996-Help Me with the Game

    【标题】"POJ2996-Help Me with the Game"是一道源自北京大学在线判题系统POJ的编程竞赛题目。这道题目的主要目标是编写程序来解决一个特定的游戏策略问题,要求参赛者具备扎实的算法基础和编程能力。 【描述】...

Global site tag (gtag.js) - Google Analytics