Tsinghua OJ 多米诺骨牌(domino)

多米诺骨牌(domino)


(domino.c/cpp)

问题描述

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

输入数据

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

输出数据

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

样例输入
4
样例输出
6
样例解释

  有四种不美观的排列。

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

数据范围

  20%的数据,n<=60;

  50%的数据,n<=6000;

  100%的数据,n<=10000。

  时间限制: 1 sec

  空间限制: 256 MB

思路:首先先计算美观的排列个数,推导可知美观的排列个数T(n)=T(n-1)+T(n-2),且T(1)=2;T(2)=4;最后用总的排列次数2^n-T(n)就是不美观的排列次数,难点是大数的加减,需要用到高精度加减法。

#include<iostream>
#include<stdio.h>
using namespace std;
const int length = 100000000;
const int L2 = 380;
void HighPreAdd(int add1[], int add2[] ,int add3[])//高精度加法
{
	int j = 0, c = 0;//c进位标志
		while (add2[j] != -1 || (c == 1))//若最高8位为-1且无进位,则退出循环
		{
			int m;
			if (add2[j] == -1)
			{
				add3[j] = c;
				c = 0;
			}
			else if (add1[j] == -1)
			{
				add3[j] = add2[j] + c;
				c = 0;
			}
			else
			{
				m = add1[j] + add2[j] + c;
				if (m >= length)
				{
					c = 1;
					m -= length;
					add3[j] = m;
				}
				else
				{
					add3[j] = m;
					c = 0;
				}

			}
			j++;
		}
}
void HighPreSub(int sub1[], int sub2[])//高精度减法
{
	int j = 0;
	while (sub1[j]!=-1)//循环到被减数的最高位+1时退出
	{
		sub2[j] = sub2[j]-sub1[j];
		j++;
	}
	for (int n = 0;n < j;n++)
	{
		if (sub2[n] < 0)
		{
			sub2[n + 1]--;
			sub2[n] += length;
		}
	}
}
int main()
{
	int num,t,count=0, *p;
	int *Add1=new int[L2];//2个操作数;
	int *Add2=new int[L2];
	int *TN = new int[L2];//TN为美观的数量,total一开始为总的排列次数,后为完美排列的次数。
	int *total = new int[L2];
	for (int i = 0;i < L2;i++)
	{
		Add1[i] = -1;
		Add2[i] = -1;
		TN[i] = -1;
		total[i] = -1;
	}
	Add1[0] = 2;
	Add2[0] = 4;
	cin >> num;
	for (int i = 3;i <= num;i++)
	{
		HighPreAdd(Add1, Add2,TN);
		if (i != num ) 
		{
			p = Add1;//元素互换
			Add1 = Add2;
			Add2 = TN;
			TN = p;
		}
	}
	for (int i = 0;i < L2;i++)
	{
		Add1[i] = -1;
		Add2[i] = -1;
	}
	Add1[0] = 2;
	Add2[0] = 2;
	for (int i = 1;i < num;i++)//表示2^n
	{
		HighPreAdd(Add1, Add2, total);
		if (i != num - 1)
		{
			p = Add1;
			Add1 = total;
			Add2 = total;
			total = p;
		}
	}
	HighPreSub(TN, total);//高精度减法
	while (total[count] != -1)//定位total最高8位的下标
		count++;
	count--;
	t = count;
	while ((count + 1) != 0)
	{
		if (t != count)
			printf("%08d", total[count]);
			else 
				printf("%d", total[count]);
		count--;
	}
	return 0;
}


  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值