1.按位与运算
只要有一个0就是0
2.左移右移运算
优先级高于按位与,左移就是将一个数的二进制位左移,就是扩大几个二倍
3.集合子集的个数,
每一个元素都可以包括出现或者不出现
就是所有子集数是2的n次方,包括空集包括集合本身,分别求的话要减一或者减掉2
4.递归递推五步走
1.确定状态
2.确定状态转移方程
3.进行越界检查,思考越界判断的条件是什么
4.模拟题目中的样例
5.将一个大问题拆成两个甚至多个子问题求解
5.应用场景
求方案数路径数一般都是递归递推,但是如果是最大最小值的优化一般都是动态规划
4.李白打酒
描述
话说大诗人李白,一生好饮。幸好他从不开车。
一天,他提着酒壶,从家里出来,酒壶中有酒两斗,他边走边唱:
无事街上走,提壶去打酒。逢店加一倍,遇花喝一斗。
这一路上,他一共遇到店5次,遇到花10次,已知最后一次遇到的是花,他正好把酒喝光了。
请你计算李白遇到店和花的次序,有多少种可能方案的个数。
———————————————————————————————————————————
思路:
这题是一个集合的暴力枚举,一共是15次,但是在途中,最后一个是花,所以就总共有十四个需要
枚举,所以我们只需要先枚举出他所有的子集,之后进行判断即可,判断条件如下
1.判断是否是五个店,9个花
2.酒是不是在遇到花之前还有一点
因为统计子集的个数是2的n次方,但是在店和酒就两种状态,一个是0,1(子集愿意定义啥定义
啥,但是得知道自己定义的是什么)因为是二进制所以我们要从0一直到2的n次方减一,因为2
的n次方正好是10000000几个0的形式,所以我们第一轮要枚举的是十四个所以就是n<<14左移十
四位,之后枚举出他的全部子集的个数之后得在for循环中定义,所以酒超市和花要在for循环中进
行定义。之后是一个关键if(i>>j&1)==1)或者是if(i>>j&1),(i>>j这里是为了右移i的第j位来进行判断
但是j是一个一个增加的,所以是一位一位判断逻辑与就是只要不是都是1就是0,所以写不写==1问
题都不大,因为if只要是条件为真就是1,所以为1之后我们这里是用1来代替超市,所以让超市
++之后让酒乘2,else的话只有一种情况,所以就是让花++,让酒--或者w-=1,都是可以的,之后
在for循环中判断判断如果酒大于一,商店==5(默认就确定了花等于9,因为总和是14)之后让
sum++,最后输出方案数也就是要输出sum。
———————————————————————————————————————————
代码实现
#include<iostream>
using namespace std;
int main()
{
int sum=0;
for(int i=0;i<(1<<14);i++)
{
int s=0,f=0,w=2;
for(int j=0;j<14;j++)
{
if((i>>j&1)==1)
{
s++;
w*=2;
}
else
{
f++;
w-=1;
}
}
if(w==1&&s==5)
{
sum++;
}
}
cout<<sum;
}
———————————————————————————————————————————
2.
题目描述
楼梯有 N 阶,上楼可以一步上一阶,也可以一步上二阶。
编一个程序,计算共有多少种不同的走法。
输入格式
一个数字,楼梯数。
输出格式
输出走的方式总数。
———————————————————————————————————————————
又是一个要递推实现的题,首先要思考的状态转移方程是什么(如果样例是很简单的自己能看懂数的一定要自己模拟模拟,能更快的发现状态转移方程)这题考虑的比较少不需要进行越界检查,要思考初始状态是f[1]=1,f[2]=2而不是f[0]=0,f[1]=1因为我们上的台阶都是正整数对于0来说没多大意义。表示的是在f[n]中n节台阶可以走的方案数我们可以轻易的得到f[1]=1,f[2]=2,f[3]=3,f[4]=5,f[5]=8
得到f[1]+f[2]=f[3],所以我们在开始时就要给出f[1],f[2]的值,以便于后面的计算,这点在我写的时候就没有注意到,之后用for循环计算即可‘
还有前面已经给出了f[1],f[2]的值,所以接下来再从1开始计算,就没有必要了,从3开始即可
———————————————————————————————————————————
代码展示
#include<iostream>
using namespace std;
long long f[50000];
int main()
{
f[1]=1,f[2]=2;
int n;
cin>>n;
for(int i=3;i<=n;i++)
{
f[i]=f[i-1]+f[i-2];
}
cout<<f[n];
}
———————————————————————————————————————————
本周的重点————[NOIP2002 普及组] 过河卒
题目描述
题目描述
棋盘上 A 点有一个过河卒,需要走到目标 B 点。卒行走的规则:可以向下、或者向右。同时在棋盘上 C 点有一个对方的马,该马所在的点和所有跳跃一步可达的点称为对方马的控制点。因此称之为“马拦过河卒”。
棋盘用坐标表示,A 点 (0, 0)、B 点 (n, m),同样马的位置坐标是需要给出的。
现在要求你计算出卒从 A点能够到达 B 点的路径的条数,假设马的位置是固定不动的,并不是卒走一步马走一步。
输入格式
一行四个正整数,分别表示 B 点坐标和马的坐标。
输出格式
一个整数,表示所有的路径条数。
———————————————————————————————————————————
思路:
首先需要一个偏移数组来保存图中那些马的地方,但是,在题目中提到,马每次输出的坐标是不同的,但是只要记住这个偏移量,不管是哪个坐标,都是按照这个形状分布的,之后需要通过一个for循环,a=x+dx[i],b=y+dy[i];之后我们需要定义一个g数组保存🐎,用一个f数组表示那个坐标系,dx,dy保存偏移数组的偏移量,我们要保存之后再打上标记g[a][b]=1就是说明这里是有马的不能经过,之后两个for循环分i,j来循环,之后[i][j]要到达的就是[i-1][j]+[i][j-1]
越界检查!!!
1.我们要用到else if,意思就是如果,,,,,那么做什么,最后是要加上一个否则,就是表示上面的条件你都不满足需要再另作些别的,
2.检查确定状态在这里面定义及如果自己走到自己那里,就是一条路就是f[0][0]=1
3.因为如果在同同一条线上,有马的话就是路线为0,因为没法越过马,就算是这整整一条直线也好,都是不行的所以前面的那条方案数是由后面的一个负责的即如果是i为0的话则f[i][j]=f[i][j-1]
反之亦然,
最后进行else,表示上面的条件都是不满足的,所以我们就可以通过我们的动态转移方程来实现了,最后输出f[m][n]即可,要在外面输入,这个for循环是从0到n,m的。因为从(0,0)的坐标开始
———————————————————————————————————————————
下面是代码实现了
#include <iostream>
using namespace std;
typedef long long LL;
const int N=25;
int g[N][N];
LL f[N][N];
int dx[]={-2,-1,1,2,2,1,-1,-2},dy[]={1,2,2,1,-1,-2,-2,-1};
int main()
{
int n,m,x,y;
cin>>n>>m>>x>>y;
g[x][y]=1;
for(int i=0;i<8;i++)
{
int a=x+dx[i],b=y+dy[i];
g[a][b]=1;
if(a<0||b<0)
continue;
}
for(int i=0;i<=n;i++)
for(int j=0;j<=m;j++)
{
if(g[i][j])
continue;
else if(i==0&&j==0)
f[i][j]=1;
else if(i==0)
f[i][j]=f[i][j-1];
else if(j==0)
f[i][j]=f[i-1][j];
else
f[i][j]=f[i-1][j]+f[i][j-1];
}
cout<<f[n][m]<<endl;
return 0;
}
———————————————————————————————————————————
最后也希望大家多给点打赏吧 !!!!!!!!!!!!
拜拜!!
11.20