欢迎使用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;
- 计算1111*2
- 计算1111*2*10
- 将前两步的结果相加,然后继续重复计算下一位。
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链接
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 《JAVA抽象类与接口》
- hibernate缓存之【查询缓存】
- [总结]视音频编解码技术零基础学习方法
- 技巧与错误
- [心得]UNP知识整理
- 欢迎使用CSDN-markdown编辑器
- 《JAVA异常处理》
- Tomcat 源码分析
- 线程池.md
- hoding object-1
- jquery源码笔记2-初始化函数
- 微信开发实战(2)—微信公众平台接口调试工具
- Android应用在新浪微博授权提示:文件不存在 C8998 的解决方法
- 均值滤波函数