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

【输入数据】
  只有一个正整数,即要排列的骨牌个数。
【输出数据】
  一个数,即不美观的排列个数。
【样例输入】
4
【样例输出】
6
【样例解释】
  有四种不美观的排列。
  黑黑黑黑,白白白白,黑黑黑白,白白白黑,黑白白白,白黑黑黑
【数据范围】
  20%的数据,n<=60;
  50%的数据,n<=6000;
  100%的数据,n<=10000。

  时间限制: 1 sec
  空间限制: 256 MB
【提示】
  动态规划、高精度加法。

—————————————————————————————————

【solution】
虽然只是Tutorial里面的题,虽然听说现在是小学僧的练习题(T_T),不过还真是想了辣么一会儿。算算真是已经有4年多没碰过这些东西了,为了完成这门课作业也真是找回了当初的感觉,真是怀念这种一道一道题“过关斩将”的感觉,已经很久不曾有这种感觉了。

回到正题。这道题初看很容易去正向考虑如何统计“不美观”的排列个数,甚至会误入使用组合数学的错误算法。根据提示,往动态规划方面想,会发现,实
际上,这道题需要反向来思考,即考虑“美观”的排列个数。那么,题目转化为求解连续颜色不超过3(不包括3)的排列个数
a,然后再用所有的排列个数(2^n)减去 a 即得问题解。再细想,这不跟动态规划的经典问题——上楼梯问题 很像吗?

于是,问题得解:
对于每一个色块(连续的 1 个或者 2
个相同颜色的白色或者黑色色块),就相当于上楼梯问题中的上升一阶或者两阶,所以这里其实我们完全可以忽略到颜色这个因素(最后再把得到的上阶梯的总数乘
以2,因为把所有的色块全部反转一次颜色都可以得到原来那种的状态的 twin
solution,而上楼梯问题并未考虑颜色问题,只是简单的划分为一次动作,这个问题正是因为颜色来划分的),而是把一个色块等同为上楼梯问题中的一次
动作。
状态方程为:f[n] = f[n-1] + f[n-2]。初始条件 f[1] = 1; f[2] = 2。
也就是不严格对应项数的著名的斐波拉契数列。
最后的结果为 2^n - 2*f[n]。

由于问题数据规模较大,最后还要用高精度加法来实现。

【source code】

 #include <stdio.h> 

 #define L 6001
#define wei 208 void echo(int ans) //make sure printing a 4-wei number,此函数可以用格式控制方式: printf("%04d", ans); 简单代替。C++中类似使用setfill('0') setw(30)等
{
if (ans > )
{
printf("%d", ans);
}
else if (ans > )
{
printf("0%d", ans);
}
else if (ans > )
{
printf("00%d", ans);
}
else
{
printf("000%d", ans);
}
} int main(void)
{
int n, i, j, temp, pro = , cn = , an[L] = { }, a[L][wei] = { }, c[wei] = { }, ans[wei] = { };
bool zero = false; scanf("%d\n", &n); //bases for a, c and an, cn
a[][] = ; a[][] = ; c[] = ; //a[n] = a[n-1] + a[n-2]
for (i = ; i <= n; i++)
{
//Gao Jin Du Jia Fa
pro = ;
for (j = ; j <= an[i - ]; j++)
{
temp = a[i - ][j] + a[i - ][j] + pro;
a[i][j] = temp % ;
pro = temp / ;
}
if (pro > )
{
a[i][j] = pro;
an[i] = j;
}
else an[i] = an[i - ];
} // 2^n
for (i = ; i < n; i++)
{
//Gao Jin Du Jia Fa
pro = ;
for (j = ; j <= cn; j++)
{
temp = c[j] * + pro;
c[j] = temp % ;
pro = temp / ;
}
if (pro > )
{
c[j] = pro;
cn++;
}
} //ans = 2^n - a[n] *2, Gao Jin Du Jia Fa
pro = ;
for (j = ; j <= an[n]; j++)
{
temp = a[n][j] * + pro;
a[n][j] = temp % ;
pro = temp / ;
}
if (pro > )
{
an[n]++;
a[n][j] = pro;
} pro = ;
for (j = ; j <= cn; j++)
{
temp = c[j] - a[n][j] + pro;
if (temp < )
{
ans[j] = temp + ;
pro = -;
}
else
{
ans[j] = temp;
pro = ;
}
} //print the answer, ignoring the zeros in the front
for (i = cn; i >= ; i--)
{
if (!zero)
{
if (ans[i] != )
{
printf("%d", ans[i]);
zero = true;
}
}
else echo(ans[i]);
}
printf("\n"); return ;
}

【代码改进空间】
1、将高精度算法函数化;
2、仍然只能通过 Tsinghua Online Judge 40%的数据,其他数据都是Runtime error (exitcode: 11),暂无果。

【优化后AC的代码】
感谢@Plan能抽出时间来AC这道题,同时找到了字符串的高精度加法解决办法,过了100%的数据。以下是参考了她的代码后自己重新几乎是照着写的代码(求2^n的函数从递归形式改成了循环版):

 #include <stdio.h>
#include <string.h>
#include <stdlib.h> char *add(char a[], char b[])
{
int len, i, j, k, up, x, y, z;
char *c, *back; len = (strlen(a) > strlen(b)) ? strlen(a) + : strlen(b) + ;
c = (char *)malloc(len*sizeof(char));
back = (char *)malloc(len*sizeof(char)); i = strlen(a) - ;
j = strlen(b) - ;
k = ; up = ; while (i >= || j >= )
{
if (i<) x = ''; else x = a[i];
if (j<) y = ''; else y = b[j];
z = x - '' + y - '';
if (up == ) z += ;
if (z>)
{
up = ; z %= ;
}
else up = ;
c[k++] = z + '';
i--; j--;
}
if (up) c[k++] = '';
c[k] = '\0'; //reverse
i = ;
for (k -= ; k >= ; k--) back[i++] = c[k];
back[i] = '\0'; return back;
} char *sub(char a[], char b[])
{
int len, i, j, k, down, x, y, z;
char *c, *back; len = strlen(a);
c = (char *)malloc(len*sizeof(char));
back = (char *)malloc(len*sizeof(char)); i = strlen(a) - ;
j = strlen(b) - ;
k = ; down = ; while (i >= || j >= )
{
if (i<) x = ''; else x = a[i];
if (j<) y = ''; else y = b[j];
z = x - '' - (y - '') - down;
if ( z < )
{
down = ;
z = z + ;
}
else down = ;
c[k++] = z + '';
i--; j--;
}
while (c[--k] == '') ; //reverse
i = ;
for (k; k >= ; k--)
{
back[i++] = c[k];
} return back;
} char *power(int n)
{
int i;
char *temp=""; for (i = ; i <= n; i++)
{
temp = add(temp, temp);
} return temp;
} char *fib(int n)
{
char *p = "", *q = "";
char *s = "";
int i; for (i = ; i < n - ; i++)
{
s = add(p, q);
p = q;
q = s;
} return s;
} int main()
{
int n;
char *mi, *f; scanf("%d\n", &n); mi = power(n);
f = fib(n);
f = add(f, f); printf("%s\n", sub(mi, f)); return ;
}

【参考资料】
1:http ://www.cnblogs.com/kuangbin/archive/2011/07/22/2113836.html 高精度加法的C++实现;
2:http://blog.sina.com.cn/s/blog_993d2542010143qw.html Fibonacci数列的第N项 log(N)算法(未用到)。

有几点:
1)由于数据规模,四位进一次位的int版高精也无法AC掉所有数据,只能用string来解决了。
2)要注意高精度运算string的顺序是不是跟数字顺序一致,所以代码中有reverse操作。

【Tsinghua OJ】多米诺骨牌(domino)问题的更多相关文章

  1. 【LeetCode】1128. Number of Equivalent Domino Pairs 等价多米诺骨牌对的数量(Python)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 字典统计 代码 复杂度分析 日期 题目地址:http ...

  2. LeetCode.1128-等价多米诺骨牌对的数量(Number of Equivalent Domino Pairs)

    这是小川的第394次更新,第428篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第259题(顺位题号是1128).给定多米诺骨牌列表,当且仅当(a == c且b == d ...

  3. [LeetCode] Push Dominoes 推多米诺骨牌

    There are N dominoes in a line, and we place each domino vertically upright. In the beginning, we si ...

  4. poj 1717==洛谷P1282 多米诺骨牌

    Dominoes Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 6571   Accepted: 2178 Descript ...

  5. 省选训练赛第4场D题(多米诺骨牌)

    题目来自FZU2163 多米诺骨牌 Time Limit: 1000 mSec    Memory Limit : 32768 KB  Problem Description Vasya很喜欢排多米诺 ...

  6. 【01背包】洛谷P1282多米诺骨牌

    题目描述 多米诺骨牌有上下2个方块组成,每个方块中有1~6个点.现有排成行的 上方块中点数之和记为S1,下方块中点数之和记为S2,它们的差为|S1-S2|.例如在图8-1中,S1=6+1+1+1=9, ...

  7. 多米诺骨牌放置问题(状压DP)

    例题: 最近小A遇到了一个很有趣的问题: 现在有一个\(n\times m\)规格的桌面,我们希望用\(1 \times 2\)规格的多米诺骨牌将其覆盖. 例如,对于一个\(10 \times 11\ ...

  8. P1282 多米诺骨牌 (背包变形问题)

    题目描述 多米诺骨牌有上下2个方块组成,每个方块中有1~6个点.现有排成行的 上方块中点数之和记为S1,下方块中点数之和记为S2,它们的差为|S1-S2|.例如在图8-1中,S1=6+1+1+1=9, ...

  9. P1282 多米诺骨牌

    P1282 多米诺骨牌 题目描述 多米诺骨牌有上下2个方块组成,每个方块中有1~6个点.现有排成行的 上方块中点数之和记为S1,下方块中点数之和记为S2,它们的差为|S1-S2|.例如在图8-1中,S ...

随机推荐

  1. Pictures of Ascii Art

    简述 指尖上的艺术 - 通过键盘上韵律般的敲敲打打,一幅幅美轮美奂的艺术作品便跃然于屏. 这样的画作,包含了无穷的创意,糅合了现代计算机科技与传统绘画艺术,难道还有比这更令人陶醉的美妙事物吗? 简述 ...

  2. struts2视频学习笔记 15-17 (访问或添加request属性,文件上传)

    课时15 访问或添加request/session/application属性 1.简单说 page指当前页面.在一个jsp页面里有效 2.request 指从http请求到服务器处理结束,返回响应的 ...

  3. Objective-C(二、类和对象)

     类和对象 #import是include的升级版,可以自动防止重复包含,所以注意:大家以后在引入头文件的时候都使用import Foundation是一个框架,Foundation.h是Founda ...

  4. loadrunner 参数化数据更新方式

    数据分配方式: Select next row[选择下一行]: 顺序(Sequential):按照参数化的数据顺序,一个一个的来取. 随机(Random):参数化中的数据,每次随机的从中抽取数据. 唯 ...

  5. 所思所想 关于asp.net界面业务分离

    1.体会:使用ASP.NET控件来做前段是有很大的局限性的 2.使用拼接HTML的方式来写代码虽然不符合模式,但是有很大的灵活性 3.如果使用拼接字符串的方式来生成前台的代码,使用NV的话完全可以实现 ...

  6. 回车键Enter

    兼容IE与firefox火狐的回车事件(js与jquery) 原生Javascript写法: <script> document.onkeydown=function(event) { e ...

  7. Swift - 自动布局库SnapKit的使用详解3(约束优先级,约束做动画)

    1,约束优先级我们使用SnapKit的时候,还可以定义约束的优先级.这样当约束出现冲突的时候,优先级高的约束覆盖优先级低的约束.具体优先级可以放在约束链的结束处. (1)可以设置如下几种优先级 pri ...

  8. 【bzoj2281】[Sdoi2011]黑白棋

    博弈论---Nimk问题. dp再搞搞. 很容易看出,该游戏的终态是每两个棋子都紧靠着.当一颗棋子移动,另一方与该棋子对应的那一刻可以立即追上,使得仍旧紧靠,最终棋子动弹不得,游戏结束. 还能看出,对 ...

  9. [Js]弹性运动

    描述:像弹簧一样左右弹动,最后缓慢停下来 一.加减速运动 1.加速运动 var iSpeed=0;iSpeed++; 速度越来越快,最后冲出去 2.减速运动 var iSpeed=20;iSpeed- ...

  10. JSON.NET 教程(一)

    下载地址:http://www.newtonsoft.com/json 参考官网文档:http://www.newtonsoft.com/json/help/html/SerializingJSON. ...