欢迎使用CSDN-markdown编辑器

来源:互联网 发布:淘宝店卖家界面 编辑:程序博客网 时间:2024/05/18 01:03

清华TsinghuaOJ 多米诺问题(Domino)

多米诺骨牌(domino)

问题描述
  小牛牛对多米诺骨牌有很大兴趣,然而她的骨牌比较特别,只有黑色和白色的两种。她觉得如果存在连续三个骨牌是同一种颜色,那么这个骨牌排列便是不美观的。现在她有n个骨牌要来排列,她想知道不美观的排列的个数。由于数字较大,数学不好的她不会统计,所以请你来帮忙。希望你帮她求出不美观的排列的个数。

输入数据
  只有一个正整数,即要排列的骨牌个数。

输出数据
  一个数,即不美观的排列个数。

样例输入

4
样例输出

6
样例解释

  有四种不美观的排列。

  黑黑黑黑,白白白白,黑黑黑白,白白白黑,黑白白白,白黑黑黑

数据范围
  20%的数据,n<=60;

  50%的数据,n<=6000;

  100%的数据,n<=10000。

  时间限制: 1 sec

  空间限制: 256 MB

提示
  动态规划、高精度加法。

因为学堂在线公开课的原因,有幸接触到了清华OJ平台。看到新手练习就想试试自己到底在什么样一个水平,在这个问题卡了一下,不过最后还是完满的解决了。

首先看到这个问题,第一时间想到的是排序问题,但是发现提示里面有动态规划。之前在《运筹学》这门课中学过动态规划的内容,但是放到这里,发现怎么都和学的内容沾不上边,直到发现同学的博客。(http://www.jianshu.com/p/bb1ba15d586c)然后恍然大悟,这个说得动态规划就是在计算菲波那切数列时的方法,明白了这一点就开始动手了。

因为其中涉及到的内容

> 高精度加减法> 动态规划

动态规划

动态规划主要用来计算菲波那切数列,可以将计算菲波那切数列的算法复杂度控制在O(n),当然还有能将代码复杂度缩减的方法,读者可以自己搜索,尝试。
char* computeFn(int n){    char *fn = new char[1];    char *gn = new char[1];    fn = "1";    gn = "0";    if (n > 1) {        while (0 < n--) {            char *temp = (char*)malloc((strlen(fn) + 1) * sizeof(char));            strncpy(temp, fn, strlen(fn) + 1);            fn = addBigNumber(fn, gn, fn);            gn = temp;        }        return fn;    }    else {        if (n == 0) {            return gn;        }        else {            return fn;        }    }}

高精度运算的代码

加法

由于数据的规模已经超过了简单的int型数据的范围,所以需要String来实现数字的运算,基本过程就利用char[]进行每一位的计算,在进行下一位的计算时进位或者不进位。最后返回结果。
//高精度加法的计算,将数字转换为字符串,进行加减

char* addBigNumber(char a[], char b[], char *result){    int aSize, bSize, resultSize;    aSize = strlen(a);//获取a字符数组的大小    bSize = strlen(b);//获取b字符数组的大小    //判断a,b两个数字串的长度    aSize > bSize ?        resultSize = aSize + 2        : resultSize = bSize + 2;    //根据最长的数字串的长度确定结果的长度    char *resultP = (char*)malloc(resultSize * sizeof(char));    resultP[resultSize - 1] = '\0';    resultSize--;    int m = 0;//当前位计算结果    bool n = false;//进位标志    int x, y;    //循环加    while (aSize > 0 || bSize > 0) {        if (n == true) {            m = 1;        }        if (aSize == 0) {            x = 0;        }        else        {            x = a[aSize - 1] - '0';            aSize--;        }        if (bSize == 0) {            y = 0;        }        else {            y = b[bSize - 1] - '0';            bSize--;        }        //cout << x << "," << y << endl;        m += x + y;        if (m > 9) {            resultP[resultSize - 1] = m - 10 + '0';            n = true;        }        else {            resultP[resultSize - 1] = m + '0';            n = false;        }        m = 0;        resultSize--;    }    //确定最大位是否存在,及是不是多一位    if (n) {        resultP[0] = '1';        result = resultP;    }    else {        resultP[0] = '0';        char *p = (char*)malloc((strlen(resultP)) * sizeof(char));        for (int i = 0; i < strlen(resultP) - 1; i++) {            p[i] = resultP[i + 1];        }        p[strlen(resultP) - 1] = '\0';        result = p;    }    //for (int i = 0; i < strlen(result); i++)    //{    //  cout << result[i];    //}    //cout << endl;    return result;}

乘法

计算乘法的原理和列竖式是一样。例如计算1111*2222

  1. 计算1111*2
  2. 计算1111*2*10
  3. 将前两步的结果相加,然后继续重复计算下一位。
char* multiply(char *a, char*b){    int aSize = strlen(a);//get size of number string a    int bSize = strlen(b);//get size of number string b    int resultPSize = aSize + 2;//定义结果字符串的大小    char* resultP = (char*)malloc(resultPSize * sizeof(char));//初始化结果字符串的指针    int resultPFinalSize = aSize + bSize + 1;    char* resultPFinal = (char*)malloc(resultPSize * sizeof(char));//初始化最终结果字符串的指针,大小的计算最大为两个数的大小之和加结束'\0'字符;    resultP[resultPSize - 1] = '\0';    resultPFinal[resultPFinalSize - 1] = '\0';    *resultPFinal = { 0 };    int m = 0;//当前位计算结果    int n = 0;//下一位进的结果    int x, y;//定义相乘的两个数    for (int i = bSize - 1; i >= 0; i--)     {        int tempI = resultPSize - 1;        for (int j = aSize - 1; j >= 0; j--)         {            if (n > 0) {                m = n;                n = 0;//计算下一位时,将进得的n赋值给m,同时重置n            }            x = a[j] - '0';//通过见过'0'字符,求得当前的数            y = b[i] - '0';            n = (int)(m + x*y) / 10;//获取积的十位数            m = (m + x*y) % 10;//获取积的个位数            tempI--;            resultP[tempI] = m + '0';            m = 0;        }        char *p;        int pSize = resultPSize + bSize - i - 1;//根据乘法算式,在每次想乘的结果后面加0        //判断是否最后会多一位        if (n > 0) {            //多一位            p = (char*)malloc(pSize * sizeof(char));//初始化字符数组大小            p[pSize - 1] = '\0';//在最后设置结束符            p[0] = n+'0';//设置第一位为n            for (int g = 1; g < resultPSize - 1; g++)             {                p[g] = resultP[g];//resultP的每一位进行赋值            }            for (int g = resultPSize - 1; g < pSize - 1; g++)            {                p[g] = '0';            }        }        else {            p = (char*)malloc((pSize - 1) * sizeof(char));            p[pSize - 2] = '\0';//在最后设置结束符            for (int g = 0; g < resultPSize - 2; g++)             {                p[g] = resultP[g + 1];//resultP的每一位进行赋值            }            for (int g = resultPSize - 2; g < pSize - 2; g++)            {                p[g] = '0';            }        }        resultPFinal = addBigNumber(resultPFinal, p, resultPFinal);//通过大数相加计算乘法算式    }    return resultPFinal;}

减法

减法的计算原理和加法类似,分别计算每一位,然后如果不够进行减法的,那么向前一位借1。

char* subtract(char *a,char *b) {    int aSize = strlen(a);    int bSize = strlen(b);    char *result = (char*)malloc((aSize + 1) * sizeof(char));    *result = { 0 };    result[aSize] = '\0';    int x, y;    int m = 0; int n = 0;    int j = aSize - 1;    for (int i = bSize - 1; i >= 0; i--,j--) {        x = a[j];        y = b[i];        if (x >= y) {            m = x - y;            n = 0;        }        else {            m = x + 10 - y;            n = -1;        }        result[j] = m+'0';        if (n == -1) {            a[j - 1] = a[j - 1] - 1;        }    }    for (; j >= 0; j--) {        if ((a[j] - '0') < 0) {            a[j]=a[j] + 10;            a[j - 1] = a[j - 1] - 1;        }        result[j] = a[j];    }    int s = 0;    for (int i = 0; i < strlen(result); i++)    {        if (result[i] == '0') {            s++;        }        else {            break;        }    }    char * resultf = (char*)malloc((aSize - s + 1) * sizeof(char));    resultf[aSize - s] = '\0';    for (int i = s; i < aSize; i++) {        resultf[i - s] = result[i];    }    return resultf;}

做完这个问题以后,加上初级训练,算是解决了8个问题了,从简单到复杂,开始涉及算法的内容,慢慢的喜欢上了这个过程。之前一直在用Java,写Web,写Android,很多事情不去考虑,现在开始用C++的时候发现自己还欠缺很多。慢慢学习吧.

本文代码GitHub链接

0 0
原创粉丝点击