HDU 递推求解专题练习 2045 2046 2047 2048 2049 2050

2045不容易系列之(3)—— LELE的RPG难题

  • 题目

  • 不容易系列之(3)—— LELE的RPG难题

  • 分析

1个格子的时候   3种

2个格子的时候   6种

3个格子的时候   6种

4个格子的时候:

      分两种情况:

  1. 前3个格子符合所有规则,即间隔颜色不同,同时第1个和第3个颜色也不同。这时候第4个格子只有1种选择
  2. 前3个格子不符合所有规则,即间隔颜色不同,但是第1个和第3个颜色相同。这时候,第4个格子有2种选择


那么怎么计算有4个格子的情况呢?


设函数f(n), f(1) = 3; f(2) = 6; f(3) = 6;

f(4) = f(3) + 2*f(2)=18;


当有n个格子,也分为两种情况,我们只需要考虑最后2个格子的情况

  1. 前n-1个格子符合所有规则,即间隔颜色不同,同时第1个和第n-1个颜色也不同。这时候第n个格子只有1种选择。前边n-1个格子有f(n-1)中涂法
  2. n-1个格子不符合所有规则,即间隔颜色不同,但是第1个和第n-1个颜色相同。这时候,第n个格子有2种选择。那么前n-2个格子有f(n-2)种可能,这种情况下有2*f(n-2)种


从而有递推公式:f(n) = f(n-1) + 2*f(n-2)

  • 代码

#include <stdio.h>

#define MAX 55

_int64 f_array(int);


int main()
{
	int n;
	__int64 res;

	while(scanf("%d", &n) != EOF)
	{
		if(n <= 0 || n > 50)
		{
			printf("Input error!Please try again!\n");
			break;

		}
		res = f_array(n);
		printf("%I64d\n", res);
	}
	return 0;
}

__int64 f_array(int n)
{
	__int64 a[MAX] = {
	0,3,6,6
	};
	int i;

	for(i = 4; i <= n; i++)
	{
		a[i] = 2*a[i-2] + a[i-1];
	}

	return a[n];
}


2046 骨牌铺方格

  • 题目

  • 骨牌铺方格

  • 分析

n = 1,一种方案

n = 2,两种方案

n = 3,三种方案

n = 4,五种方案

..........

n = N 呢?

如果对数字比较敏感,那么可以看出这会是一个斐波那契问题。

当有n格时,分两中情况:

  1. 如果打算第n格竖着放,那么前边n - 1格可以任意摆放,共有f(n-1)种方法;
  2. 如果打算第n格横着放,那么要求第n - 1格也横着放。前n-2格可以任意摆放,共有f(n-2)种方法;

从而,总的方法f(n) = f(n-1) + f(n - 2)

  • 代码

#include <stdio.h>


#define MAX 55

__int64 f(int);
int main()
{
	int n;
	__int64 res;

	while(scanf("%d", &n) != EOF)
	{
		if(n <= 0 || n > 50)
		{
			printf("Input error!\n");
			break;
		}
		res = f(n);
		printf("%I64d\n", res);
	}
	return 0;

}


__int64 f(int n)
{
	int i;
	__int64 a[MAX] = {
		0, 1, 2, 3
	};
	for (i = 4; i <= n; i++)
	{
		a[i] = a[i-1] + a[i-2];
	}
	return a[n];
}

2047 阿牛的EOF牛肉串

题目

阿牛的EOF牛肉串

分析

本题不同于RPG难题,RPG难题是从前往后推,我们先确定第n-1个方格的涂色情况,然后在确定第n格可以涂哪几种颜色。

本题先考虑第n格可以填哪几个字母,再往前推。

两种情况:

  • 第n格填‘E’或’F’,那么第n-1格可以填任意字符串,第n-2格有f(n-1)种方法
  • 第n格填‘o’,那么第n-1格一定填'E'或'F',此时第n-2格有f(n-2)种方法

所有,有

         f(n) = 2 * [f(n-1) + f(n-2)]

代码

#include <stdio.h>

int main()
{
	int i, n;
	
	__int64 temp, pre_res, res;

	while(scanf ("%d", &n) != EOF)
	{
		if(n <= 0 || n >= 40)
			break;
		pre_res = 3;
		res = 8;
		if(n == 1)
			printf("%I64d\n", pre_res);
		else if(n == 2)
			printf("%I64d\n", res);
		else
		{
			for(i = 3; i <= n; i++)	
			{
				temp = res;
				res = 2*(pre_res + res);
				pre_res = temp;
			}
			printf("%I64d\n", res);
		}

	}
	return 0;


}


2048 神、上帝以及老天爷

题目

2048

分析

本题考察错排。所以,不知道错排的概念就不知道如何下手。

错排定义:维基百科定义

我们采用递推的方法研究错排公式:

       当n个编号元素放在n个编号位置,用f(n)表示元素编号与位置编号不对应的错排数.

       显然f(1)=0,f(2)=1。当n≥3时,不妨设n排在了第k位,其中k≠n,也就是1≤k≤n-1。那么我们现在考虑第n位的情况。

  • 当k排在第n位时,除了n和k以外还有n-2个数,其错排数为f(n-2)

  • 当k不排在第n位时,那么将第n位重新考虑成一个新的“第k位”,这时的包括k在内的剩下n-1个数的每一种错排,都等价于只有n-1个数时的错排(只是其中的第k位会换成第n位)。其错排数为f(n-1)

       综上得到:

                     f(n)=(n-1)*[f(n-1)+f(n-2)],其中:f(1)=0,f(2)=1

有了这个递推公式就好办了,我们先求出错排的总数,然后再求出所有情况总数(就是n的阶乘)。最后,输出两位的百分比数。

代码

#include <stdio.h>

int main()
{
	int c, n, i;
	long long pre_res, res, temp, denom;

	/* 输入行数 */
	while(scanf("%d", &c) != EOF)
	{
		while(c--)
		{
			scanf("%d", &n);
			if(n <= 1 || n > 20)
				return 0;
			pre_res = 0;
			res = 1;
			if (n > 2)
			{
				/* 求错排总数 */
				for(i = 3; i <= n; i++)
				{
					temp = res;
					res = (i-1) * (pre_res + res);
					pre_res = temp;
				}
			}

			/* 初始化分母为1 */
			denom = 1;

			/* 计算n的阶乘 */
			for(i = 1; i <= n; i++)
			{
				denom *=i;
			}
			printf("%.2lf%%\n", (double)res/denom*100);
		}
	}
	return 0;
}


2049 不容易系列之(4)——考新郎

题目

2049

分析

理解了2048题之后,再来看本题,你会发现这一题的本质还是个错排问题。

区别在于

  • 需要先从n对新婚夫妇中选取m个新郎来进行错排
  • 不需要求概率,求出多少中可能的情况即可

代码

#include <stdio.h>

int main()
{
	int c, m, n, i;
	long long  pre_res, res, temp;//求错排
	long long fac, denom, numer; //求组合数

	while(scanf("%d", &c) != EOF)
	{
		while(c--)
		{
			scanf("%d%d", &n, &m);
			if (m > n || m > 20 || n <= 1)
				break;
			/* m个新郎找错新娘的情况种类 */

			pre_res = 0;
			res = 1;
			for(i = 3; i <= m; i++)
			{
				temp = res;
				res = (i - 1)*(pre_res + res);
				pre_res = temp;
			}

			/* 从n对新婚夫妇中,选取m个犯错的新郎 */
			denom = numer = 1;

			for(i = 0; i < m; i++)
			{
				numer *= (n-i);
				denom *= (m-i);
			}

			fac = numer/denom;
			printf("%lld\n", fac * res);


		}
	}
}


2050 折线分割平面

题目

2050

分析

  • 我们首先看n条直线分平面问题

      题目大致如:n条直线,最多可以把平面分为多少个区域
      分析:当有n-1条直线时,平面最多被分成了f(n-1)个区域。则第n条直线要是切成的区域数最多,就必须与每条直线相交且不能有同一交点。 这样就会得到n-1个交点。这些交点将第n条直线分为2条射线和n-2条线段。而每条射线和线段将以有的区域一分为二。这样就多出了2+(n-2)个区域。
       故:f(n)=f(n-1)+n =

  • 折线分平面

      根据直线分平面可知,由交点决定了射线和线段的条数,进而决定了新增的区域数。当n-1条折线时,区域数为f(n-1)。为了使增加的区域最多,则折线的两边的线段要和n-1条折线的边,即2*(n-1)条线段相交。那么新增的线段数为4*(n-1),射线数为2。但要注意的是,折线本身相邻的两线段只能增加一个区域。
       故:f(n)=f(n-1)+2*[2*(n-1)+1] -1

代码


#include <stdio.h>

int main()
{
	int c, n, i;
	long long pre_res, res;

	while (scanf("%d", &c) != EOF)
	{
		while (c--)
		{
			scanf("%d", &n);
			pre_res = 2;
			if (n < 1 || n > 10000)
				return ;

			if (n == 1)
				printf("%lld\n", pre_res);
			else
			{
				for (i = 2; i <= n; i++)
				{
					res = pre_res + 2*(2*(i-1) + 1) - 1;
					pre_res = res;
				}
				printf("%lld\n", pre_res);
			}
			
		}
	}
	return 0;
}



你可能感兴趣的:(编程,递归)