注:本文为回顾,所以仅会记录本人认为的难点与分析
递推
联系&难度
个人认为,递推与动态规划实际是密不可分的,你说它简单,但到了做题时难以找到转移方程,你要是说它难,但它确确实实是最基本的东西了
例题
斐波那契数列
这是一道最基础的递推题,根据对数列的描述,不难发现,从第3项开始,我们都可以用这样一个式子表示:(f_i=f_{i-1}+f_{i-2})
因而,我们可以直接利用循环得到,代码如下:
#include <iostream>
#include <cstdio>
using namespace std;
int n,a,b[1000001],mmax = 2;
int main(){
cin >> n;
b[1] = 1;
b[2] = 1;
for (int i = 3;i <= 1000001;i ++)
b[i] = (b[i - 1] + b[i - 2]);
while (n > 0){
n --;
cin >> a;
cout << b[a] << endl;
}
return 0;
}
题目传送门:点这里
上台阶
这一道题其实可以看做一道最基础的动态规划,每一步有3个状态,我们可以发现,当楼梯有1层时,仅有1种走法;当楼梯有2层时,有2种走法:走2个1层或1个2层;当楼梯有3层时,有4种走法:一次三层,三次一层,2、1和1,2;再往后,我们可以发现,i层时可行方法为i-1层i-2层i-3层的方法数总和,即(f_i=f_{i-1}+f_{i-2}+f_{i-3}),而(f_1=1,f_2=2,f_3=4)为边界条件,进行循环,按输入得到结果即可,代码如下:
#include <iostream>
#include <cstdio>
using namespace std;
long long int n,f[72];
int main(){
f[1] = 1;
f[2] = 2;
f[3] = 4;
for (int i = 4;i <= 71;i ++)
f[i] = f[i - 1] + f[i - 2] + f[i - 3];
while (1){
cin >> n;
if (n == 0)
break;
cout << f[n] << endl;
}
return 0;
}
题目传送门:点这里
流感传染
这一道题则就是一种搜索,其实并没有太大的难度
具体细节详见下方代码:
#include <iostream>
#include <cstdio>
using namespace std;
int n,t[101][101],o[101][101],m,ch[10001][2],last,now,ans; //o在本处并无实际用处,ch为队列,ch[x][0]为行,ch[x][1]为列,last,now分别为队列的头和尾
int main(){
cin >> n;
for (int i = 0;i < n;i ++)
for (int j = 0;j < n;j ++){
char c;
cin >> c;
if (c == '.')
t[i][j] = 0;
else if (c == '@'){
o[i][j] = t[i][j] = 1;
}
else if (c == '#')
o[i][j] = t[i][j] = -1;
} //原图的输入
cin >> m;
for (int k = 2;k <= m;k ++){ //需从第二天开始进行模拟
for (int i = 0;i < n;i ++)
for (int j = 0;j < n;j ++)
if (t[i][j] == 1){ //如果该点为感染者
if (i - 1 >= 0) //保证不越界
if (t[i - 1][j] == 0){ //若该点为正常人
ch[now][0] = i - 1; //存储坐标
ch[now][1] = j;
now ++; //队尾++
}
if (j - 1 >= 0) //同上
if (t[i][j - 1] == 0){
ch[now][0] = i;
ch[now][1] = j - 1;
now ++;
}
if (t[i + 1][j] == 0){
ch[now][0] = i + 1;
ch[now][1] = j;
now ++;
}
if (t[i][j + 1] == 0){
ch[now][0] = i;
ch[now][1] = j + 1;
now ++;
}
}
for (int i = last;i < now;i ++){
t[ch[i][0]][ch[i][1]] = 1; //将队列所做更改写入图
}
last = now;//清空队列
}
for (int i = 0;i < n;i ++) //统计
for (int j = 0;j < n;j ++)
if (t[i][j] == 1)
ans ++;
cout << ans ;
return 0;
}
题目传送门:点这里
递归(搜索与回溯)
联系&难度
搜索与回溯,即深度优先搜索(DPS),属于递归的一种,而且,许多递推可做的题目同样可用递归做出,如:斐波那契数列
例题
八皇后问题
这一道题可以说是十分基础了,基本是必会的题目,主体思想很简单,从第一个皇后的位置进行选择,然后依次判断此行每个位置是否可以放下,如果是,进行递归,如果不行,判断下一位置,然后进行回溯
#include<iostream>
#include<cstdio>
using namespace std;
int a[30];
int b[30];
int c[30];
int d[30];
int flag=0;
void print()
{
flag++;
cout<<"No. "<<flag<<endl;
for(int i=1;i<=8;i++)
{
for(int j=1;j<=8;j++)
{
if(a[j]==i)
cout<<"1 ";
else
cout<<"0 ";
}
cout<<endl;
}
}
void searchh(int i)
{
for(int j=1;j<=8;j++)
{
if((!b[j])&&(!c[i+j])&&(!d[i-j+7]))
{
a[i]=j;
b[j]=1;
c[i+j]=1;
d[i-j+7]=1;
if(i==8) print();
else searchh(i+1);
b[j]=0;
c[i+j]=0;
d[i-j+7]=0;
}
}
}
int main()
{
searchh(1);
return 0;
}
题目传送门:点这里
更新日志
- 2020.5.16 完成编辑
日后优化持续跟进