最近好慌啊
东北赛打铁了,虽说是意料之内,但还是好气啊
递推求解专题练习(For Beginner)
/*HDOJ2044 有一只经过训练的蜜蜂只能爬向右侧相邻的蜂房,不能反向爬行。请编程计算蜜蜂从蜂房a爬到蜂房b的可能路线数。
其中,蜂房的结构如下所示。*/
#include<stdio.h>
long long fun(long long x);
long long arr[60]={1,1};
int main(void)
{
int n;
long long a,b;
scanf("%d",&n);
while(n-->0){
scanf("%lld %lld",&a,&b);
printf("%lld\n",fun(b-a));
}
return 0;
}
long long fun(long long x)//记忆化递归写法
{
if(x==1)
return arr[x];
else if(x==0)
return arr[x];//从x到x也是一种走法
if(arr[x]!=0)
return arr[x];
else
return arr[x]=fun(x-1)+fun(x-2);
}
又见斐波那契数列
//有些类似圆排列,但是有确定起点
//考虑当前格子时,一定不会与1相同。但是考虑下一个格子时,要额外考虑上一个格子与第一个相同的情况
#include<cstdio>
#include<iostream>
using namespace std;
int main()
{
long long arr[55]={0,3,6,6};
int i;
for(i=4;i<52;i++){//涂第n个格子时,n-1有两种情况:与1相同或不同。
//不同的话,只能填剩下的一种。这部分=F(n-1)。
//1与n-1相同的话,可以填与1不同的两种,对应情况F(n-2)*2
arr[i]=arr[i-1]+arr[i-2]*2;
}
int n;
while(cin>>n)
cout<<arr[n]<<endl;
return 0;
}
考虑当前格子时,一定不会与1相同。但是考虑下一个格子时,要额外考虑上一个格子与第一个相同的情况。
涂第n个格子时,n-1有两种情况:与1相同或不同。
①不同的话,只能填剩下的一种。这部分=F(n-1)。
②1与n-1相同的话,可以填与1不同的两种,对应情况F(n-2)*2。
递推公式:F(n)=F(n-1)+F(n-2)*2
#include<iostream>
using namespace std;
int main()
{
long long arr[55]={0,1,2,3},i;
for(i=4;i<55;i++)
arr[i]=arr[i-1]+arr[i-2];
int n;
while(cin>>n)
cout<<arr[n]<<endl;
return 0;
}
这个很容易看出来……
//HDOJ-2047阿牛的EOF牛肉串
//递推,三个字符,第n位与第n-1位是不是O有关
//假如n为O,n-1一定不为O,n-2任意,n-1为E或F,这部分为F(n-2)*2
//假如n不为O,n-1可以随便取,n为E或F,F(n-1)*2
#include<iostream>
using namespace std;
int main()
{
long long arr[45]={0,3,8},i;
for(i=3;i<45;i++)
arr[i]=2*arr[i-1]+2*arr[i-2];
int n;
while(cin>>n)
cout<<arr[n]<<endl;
return 0;
}
三个字符,第n位与第n-1位是不是O有关
①假如n为O,n-1一定不为O,n-2任意,n-1为E或F,这部分为F(n-2)*2
②假如n不为O,n-1可以随便取,n为E或F,F(n-1)*2
递推公式:F(n)=F(n-2)*2+F(n-1)*2
//设第n项错排数为F(n),则n-1项为F(n-1)
//1.将第n个元素放在其他位置,一共有n-1种,假设放在第k个位置
//2.放置第k个元素,有两种可能:
//①k放在第n个位置,n放在k的位置,剩下n-2个元素错排,一共F(n-1)种可能
//②k不放在第n个位置,n-1个元素错排,一共F(n-2)种可能
//递推公式F(n)=(n-1)*[F(n-2)+F(n-1)]
#include<cstdio>
#include<iostream>
using namespace std;
int main()
{
long long F[30]={0,0,1},all=2;//all是所有组合的可能个数
double rate[30]={0,0,0.5};
int i,t;
for(i=3;i<22;i++){
F[i]=(i-1)*(F[i-2]+F[i-1]);
all*=i;
rate[i]=(double)F[i]/all;
}
int c;
cin>>c;
while(c--){
cin>>t;
printf("%.2lf%%\n",rate[t]*100);
}
return 0;
}
全错位排列
设第n项错排数为F(n),则n-1项为F(n-1)
1.将第n个元素放在其他位置,一共有n-1种,假设放在第k个位置
2.放置第k个元素,有两种可能:
①k放在第n个位置,n放在k的位置,剩下n-2个元素错排,一共F(n-1)种可能
②k不放在第n个位置,n-1个元素错排,一共F(n-2)种可能
递推公式F(n)=(n-1)*[F(n-2)+F(n-1)]
//错排,2048进阶
//一共有N对,选出M对进行错排,一共有C(N,M)种选法
//用错排的递推公式F(n)=(n-1)*[F(n-2)+F(n-1)]乘以组合数即为答案
#include<iostream>
#include<cstdio>
using namespace std;
long long fun(long long n,long long m);
int main()
{
long long F[25]={0,0,1},i;
for(i=3;i<22;i++){
F[i]=(i-1)*(F[i-2]+F[i-1]);
}
int C,n,m;
cin>>C;
while(C--){
cin>>n>>m;
cout<<fun(n,m)*F[m]<<endl;
}
return 0;
}
long long fun(long long n,long long m)
{
long long a=1,b=1,c=1,i;
for(i=1;i<=n;i++){
a*=i;
}
for(i=1;i<=m;i++){
b*=i;
}
for(i=1;i<=n-m;i++){
c*=i;
}
return a/(b*c);
}
错排,2048进阶
一共有N对,选出M对进行错排,一共有C(N,M)种选法。
用错排的递推公式F(n)=(n-1)*[F(n-2)+F(n-1)]乘以组合数即为答案。
//将当前加入折线看成两段,每段都与之前折线的两边有2*(n-1)个交点,每边产生2n-3个线段,1条射线,1个折角的一边
//一个射线或线段产生一个新区域,折角算一个新区域,两条共产生4n-3个新区域
#include<cstdio>
#include<iostream>
using namespace std;
int main()
{
int c,i,TAT[10005]={0,2,7};
for(i=3;i<10003;i++)
TAT[i]=TAT[i-1]+(i-1)*4+1;
cin>>c;
while(c--){
int n;
cin>>n;
cout<<TAT[n]<<endl;
}
// for(i=4;i<10003;i++)
// cout<
return 0;
}
将当前加入折线看成两段,每段都与之前折线的两边有2*(n-1)个交点,每边产生2n-3个线段,1条射线,1个折角的一边。
一个射线或线段产生一个新区域,折角算一个新区域,两条共产生4n-3个新区域
Problem Description
约19世纪末,在欧州的商店中出售一种智力玩具,在一块铜板上有三根杆,最左边的杆上自上而下、由小到大顺序串着由64个圆盘构成的塔。目的是将最左边杆上的盘全部移到右边的杆上,条件是一次只能移动一个盘,且不允许大盘放在小盘的上面。
现在我们改变游戏的玩法,不允许直接从最左(右)边移到最右(左)边(每次移动一定是移到中间杆或从中间移出),也不允许大盘放到下盘的上面。
Daisy已经做过原来的汉诺塔问题和汉诺塔II,但碰到这个问题时,她想了很久都不能解决,现在请你帮助她。现在有N个圆盘,她至少多少次移动才能把这些圆盘从最左边移到最右边?
Input
包含多组数据,每次输入一个N值(1<=N=35)。
Output
对于每组数据,输出移动最小的次数。
Sample Input
1
3
12
Sample Output
2
26
531440
#include
using namespace std;
int main(void)
{
long long st[40]={0,2,8},i,n;
for(i=3;i<37;i++){
st[i]=3*st[i-1]+2;
}
while(cin>>n)
cout<<st[n]<<endl;
return 0;
}
//woc,这题我居然独立做出来了
//一共n层,先将上面n-1层移到㈢柱,再将第n层移至㈡柱
//再将㈢柱的n-1层移到㈠柱,再将㈡柱的第n层移至㈢柱,㈠柱的n-1层也移至㈢柱
//递推公式st[i]=3*st[i-1]+2;
//好吧,确实不难(っ °Д °;)っ
#include
using namespace std;
typedef long long ll;
ll F1[30]={0,1,4},F2[30]={0,2,4};//F1为将上n-1移到相邻柱子上所需步数(下标代表移动数量),F2为整个移到最右边所需步数
//通项公式:①F2[n]=2F1[n-1]+2,②F1[n]=3F1[n-1]+1
int main()
{
int i,n,t;
for(i=3;i<=21;i++)
F1[i]=3*F1[i-1]+1;
for(i=3;i<=21;i++)
F2[i]=2*F1[i-1]+2;
cin>>t;
while(t--){
cin>>n;
cout<<F2[n]<<endl;
}
return 0;
}
分析:和上面那题结合来看,加入了新规则:允许最大的放在最上面
第一部分:
步骤一:将上面n-1个移到Ⅱ柱
步骤二:将Ⅰ柱剩下的第n片移到Ⅲ柱(这部分需要2步)
步骤三:将Ⅱ上的n-1个移到Ⅲ柱
①递推公式:F2[n]=2F1[n-1]+2
可以看出来,第一部分步骤一和步骤三消耗步数一样。
但是移动上面n-1层时不可以将最大的放在最上面,
这时求解移动上面n-1层就变成了汉诺塔Ⅲ将整体移动到相邻柱子上的情况。
第二部分:分析上面n-1层移到相邻柱子所需步数
(不管n-1层在中间还是两边,步数都是一样的,以Ⅰ移到Ⅱ为例)
步骤一:将上面n-1个移到Ⅲ柱,共2F1[n-1]步
步骤二:将Ⅰ柱剩下的第n片移到Ⅱ柱(1步)
步骤三:将Ⅲ上的n-1个移到Ⅱ柱,F1[n-1]步
这部分的递推公式②F1[n]=3F1[n-1]+1
合起来就是F2[n]=6F1[n-2]+4
Run ID | Submit Time | Judge Status | Pro.ID | Exe.Time | Exe.Memory | Code Len. | Language | Author |
---|---|---|---|---|---|---|---|---|
29471468 | 2019-06-23 14:01:07 | Accepted | 2077 | 31MS | 1800K | 420 B | C++ | Overstars |
29447707 | 2019-06-17 00:00:39 | Accepted | 2064 | 31MS | 1800K | 191 B | C++ | Overstars |
29383967 | 2019-06-04 15:55:12 | Accepted | 2049 | 31MS | 1792K | 628 B | C++ | Overstars |
29381358 | 2019-06-03 22:45:28 | Accepted | 2048 | 0MS | 1796K | 667 B | C++ | Overstars |
29324683 | 2019-05-27 19:40:39 | Accepted | 2050 | 0MS | 1832K | 529 B | C++ | Overstars |
29316064 | 2019-05-26 15:15:43 | Accepted | 2047 | 0MS | 1796K | 416 B | C++ | Overstars |
29314735 | 2019-05-26 12:40:02 | Accepted | 2046 | 0MS | 1800K | 229 B | C++ | Overstars |
29314669 | 2019-05-26 12:22:57 | Accepted | 2045 | 15MS | 1800K | 573 B | C++ | Overstars |
28760028 | 2019-03-31 08:57:52 | Accepted | 2044 | 0MS | 1696K | 420 B | C | Overstars |
2019年6月4日16点20分
2019年6月23日14点38分 加了两道汉诺塔的题