您的位置:首页 > 其它

HDU-#2044-2050 递推求解专题

2014-08-20 22:19 369 查看
HDU的#2044-2050是递推专题训练,递推关系在数学专题中是很重要的一部分,也是规律性和技巧性很强的一部分。下面给出这个专题的解题报告如下:

专题来源:【HDU递推求解专题训练题

#2044:一只小蜜蜂...

解题思路:直接递推可以发现,从1开始到每一个点的走法为:1 ,2,3,5,8....这时候很清晰的数列出现在我们面前,那就是斐波那契数列。而问题是要求给出起点到终点的走法,而不是1。但是我们反过来想想,从任何点开始走与从1开始走到他们之间差值那个点的结果是一致的。因此该问题只是斐波那契数列的变形,将a,b的差值作为n即可得到,详见code。

题目来源:http://acm.hdu.edu.cn/showproblem.php?pid=2044

code:

#include <iostream>
#include <cstdio>
using namespace std;

#define ll __int64
const int MAXN = 50+10;
int n,a,b;
ll f[MAXN];

int main(){
f[0]=1;f[1]=1;
for(int i=2;i<MAXN;i++)
f[i]=f[i-1]+f[i-2];
scanf("%d",&n);
while(n--){
scanf("%d%d",&a,&b);
printf("%I64d\n",f[b-a]);
}
return 0;
}


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

解题思路:找不到好的思路时,我们先枚举结果,可以得到:f[1]=3,f[2]=6,f[3]=6,f[4]=18,f[5]=30....,根据枚举的数列可以推导出该递推公式:f[i]=f[i-1]+2*f[i-2],这里数据量不大时可以直接枚举找下规律,要注意边界为:f[1]=3,f[2]=6,f[3]=6。注意数据范围,用__int64来存。详见code。

题目来源:http://acm.hdu.edu.cn/showproblem.php?pid=2045

code:

#include <iostream>
#include <cstdio>
using namespace std;

#define ll __int64
const int MAXN = 50+10;
int n;
ll f[MAXN];

int main(){
f[1]=3;f[2]=6;f[3]=6;
for(int i=4;i<MAXN;i++)
f[i]=f[i-1]+2*f[i-2];
while(scanf("%d",&n)!=EOF)
printf("%I64d\n",f
);
return 0;
}


#2046:骨牌铺方格

解题思路:这是一道经典的题目。首先先考虑最左边一列的铺法,若用一个直接纵向覆盖,则剩下的2*(n-1)方格有f(n-1)种铺法;若用两个横向的覆盖,则剩下的2*(n-2)有f(n-2)种铺法。因此递推可以得到f(n)=f(n-1)+f(n-2),边界f(0)=f(1)=1.恰好就是斐波那契数列,直接就可以求解。不过这里还有一种推法,就是考虑第i列纵向骨牌,则左边的i-1列和右边的n-i列各有f(i-1)和f(n-i)种铺法,根据乘法原理以及去掉重复的和加上遗漏的,可以得到另一种递推式:1、当n为偶数的时候,f(n)=1+f(1)+f(3)+...+f(n-1),其中1为没有纵向的情况;2、当n为奇数的时候,f(n)=f(0)+f(2)+f(4)+...+f(n-1)。边界为:f(0)=f(1)=1。因此这也很好地说明了递推式可能存在多种,这也是它规律性和技巧性很强的原因之一。还有就是不完善的解法可以通过打补丁来修复,不过这需要很强的逻辑和理论。解法详见code哈!

题目来源:http://acm.hdu.edu.cn/showproblem.php?pid=2046

斐波那契数列 code:

#include <iostream>
#include <cstdio>
using namespace std;

#define ll __int64
const int MAXN = 50+10;
int n;
ll f[MAXN];

int main(){
f[0]=1;f[1]=1;
for(int i=2;i<MAXN;i++)
f[i]=f[i-1]+f[i-2];
while(scanf("%d",&n)!=EOF)
printf("%I64d\n",f
);
return 0;
}


另一种code:

#include <iostream>
#include <cstdio>
using namespace std;

#define ll __int64
const int MAXN = 50+10;
int n;
ll f[MAXN];

int main(){
f[-1]=1;f[0]=1;f[1]=1;
for(int i=2;i<MAXN;i++){
if(i%2==0) for(int j=-1;j<MAXN;j+=2) f[i]+=f[j];
else for(int j=0;j<MAXN;j+=2) f[i]+=f[j];
}
while(scanf("%d",&n)!=EOF)
printf("%I64d\n",f
);
return 0;
}


#2047:阿牛的EOF牛肉串

解题思路:给长度为n的字符串,由EOF三个字符组成,排除OO相连的情况的有多少种组合。直接找规律递推就行。首先分两种情况:一是当第i位为O的时候,则i-1位只能是E or F,对于剩下n-2的情况为f(n-2),则该递推式为1*2*f[n-2];二是当第i位为E or F的时候,那么n-1位为f(n-1),该情况递推式为2*f[n-1]。综上,该递推式为f
=2*(f[n-1]+f[n-2]).详见code。

题目来源:http://acm.hdu.edu.cn/showproblem.php?pid=2047

code:

#include <iostream>
#include <cstdio>
using namespace std;

#define ll __int64
const int MAXN = 40+5;
int n;
ll f[MAXN];

int main(){
f[1]=3;f[2]=8;
for(int i=3;i<MAXN;i++)
f[i]=2*(f[i-1]+f[i-2]);
while(scanf("%d",&n)!=EOF)
printf("%I64d\n",f
);
return 0;
}


#2048:神、上帝以及老天爷

解题思路:这是一个错排问题。先求解错排的数量,然后除以全排的数量就是答案。对于错排情况:对于第n个人,则他的选取方法为n-1种;若选取第i个人的,此时有两种情况,一是该人选取的是第n个人的,则剩余的就是n-2种错排。第二种是不选取第n个人,则此时剩下的n-1种要错排。综上递推式为:f(n)=(n-1)*(f(n-1)+f(n-2))。详见code。

题目来源:http://acm.hdu.edu.cn/showproblem.php?pid=2048

code:

#include <iostream>
#include <cstdio>
using namespace std;

#define ll __int64
const int MAXN = 21;
ll c[MAXN],f[MAXN];
int t,n;

int main(){
c[1]=1;
for(int i=2;i<=MAXN;i++)
c[i]=c[i-1]*i;
f[1]=0;f[2]=1;
for(int i=3;i<=MAXN;i++)
f[i]=(i-1)*(f[i-1]+f[i-2]);
scanf("%d",&t);
while(t--){
scanf("%d",&n);
printf("%.2lf%%\n",100*(double)f
/c
);
}
return 0;
}


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

解题思路:该题是上题的一种变形的,原则上也是一种错排问题,这里要注意(n-m)个人是正确的排列,此时错排的数量要和这(n-m)个进行组合,即c(n,m)*f(n)。这里就不赘述了,详见code。

题目来源:http://acm.hdu.edu.cn/showproblem.php?pid=2049

code:

#include <iostream>
#include <cstdio>
using namespace std;

#define ll __int64
const int MAXN = 21;
ll c[MAXN],f[MAXN];
int t,n,m;

int main(){
c[0]=1;c[1]=1;
for(int i=2;i<=MAXN;i++)
c[i]=c[i-1]*i;
f[0]=0;f[1]=0;f[2]=1;
for(int i=3;i<=MAXN;i++)
f[i]=(i-1)*(f[i-1]+f[i-2]);
scanf("%d",&t);
while(t--){
scanf("%d%d",&n,&m);
printf("%I64d\n",c
/c[m]/c[n-m]*f[m]);
}
return 0;
}


#2050:折线分割平面

解题思路:这个题比较经典,这里参见了这篇博客,这里讲的比较详细和清楚,规律性比较强,直接递推就可以出来了,就不赘述了,详见code。

题目来源:http://acm.hdu.edu.cn/showproblem.php?pid=2050

code:

#include <iostream>
#include <cstdio>
using namespace std;

int n,t;

int main(){
scanf("%d",&t);
while(t--){
scanf("%d",&n);
printf("%d\n",2*n*n-n+1);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: