11.20知识整理

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

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值