HDOJ-1297 Children’s Queue(递推,大数相加)

版权声明:个人学习笔记记录 https://blog.csdn.net/Ratina/article/details/83931112

题目:HDOJ-1297

题目描述:n个人排队,女生必须和女生相邻(可以2个以上,也可以1个都没有),问有多少中排队方法。(1<=n<=1000)
例如当n=4,有7种情况,分别为 :(F为女生,M为男生)
FFFF, FFFM, MFFF, FFMM, MFFM, MMFF, MMMM

思路:(逆推思路)
对n位置情况进行讨论:
1.当n位置为M,对前n-1无影响,所以直接就等于 f(n-1)

2.当n位置为F,则n-1一定得是F,接下来对n-2位置的情况进行讨论:
 a.当n-2位置为M,对前n-2无影响,所以该情况等于 f(n-2)
 b.当n-2位置为F,n-3位置为M,对前n-4无影响,该情况等于 f(n-4)

这里为什么不对n-3位置为F进行讨论呢,因为当n-2,n-3位置均为F时,前n-2已经属于合法队列,该情况已经被包含在2-a中。
这里讨论n-2位置为F,n-3位置为M,是为了补充本身不合法,但是跟上n-1位置的F以后就合法的情况

综上所述 :f(n) = f(n-1) + f(n-2) + f(n-4)

此外,就是当n大了以后,答案是64位都存不下的,所以这题还要模拟大数相加。
我用了string来从个位开始存储大数,最后倒着输出。

以下AC代码:

#include<cstdio>
#include<string>
using namespace std;
string add(string s1, string s2)
{
	int L1 = s1.length();
	int L2 = s2.length();
	int i;
	string outcome;
	bool flag = false;     //标记是否要进位
	for (i = 0; i < L1 && i < L2;i++)    //模拟对应位置相加
	{
		int sum = (s1[i] - '0') + (s2[i] - '0');
		if (flag)
			sum += 1;
		if (sum >= 10)
		{
			flag = true;
			sum %= 10;
		}
		else
			flag = false;
		outcome += (sum + '0');
	}
	//以下用来对较长字符串的剩余部分进行处理
	if (L1 < L2)         
	{
		for (i = L1 ; i < L2; i++)
		{
			int sum = (s2[i] - '0');
			if (flag)
				sum += 1;
			if (sum >= 10)
			{
				flag = true;
				sum %= 10;
			}
			else
				flag = false;
			outcome += (sum + '0');
		}
	}
	else if (L1 > L2)
	{
		for (i = L2 ; i < L1; i++)
		{
			int sum = (s1[i] - '0');
			if (flag)
				sum += 1;
			if (sum >= 10)
			{
				flag = true;
				sum %= 10;
			}
			else
				flag = false;
			outcome += (sum + '0');
		}
	}
	if (flag)     //如果最后还有进位,要记得加上
		outcome += '1';
	return  outcome;
}
int main()
{
	string f[1001];
	int i, n;
	f[1] += '1';
	f[2] += '2';
	f[3] += '4';
	f[4] += '7';
	for (i = 5; i <= 1000; i++)
	{
		string temp;
		temp = add(f[i - 1], f[i - 2]);
		f[i] = add(temp, f[i - 4]);
	}
	while (scanf("%d", &n) != EOF)
	{
		for (i = f[n].length()-1; i >= 0; i--)   //倒序输出
			putchar(f[n][i]);
		putchar('\n');
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/Ratina/article/details/83931112
今日推荐