2021/5/23每周学习总结10

每周学习总结
这周主要学习了递归算法,深度优先搜索(DFS)和广度优先搜索(BFS),递归算法相对比较简单,因为这在第一学期就已经有所学习,所以对递归理解也比较快,而DFS和BFS则让我感到有些理解上的困难,不过这两种算法的大概思路就是枚举所有的可能,并且找出符合的答案。以下通过几道例题对几种算法进行分析。
1求快速幂

typedef long long ll;
ll binaryPow(ll a, ll b){
	if(b == 1)
		return a;
	else if(b % 2 == 1)
		return a * binaryPow(a, b - 1) ;
	else{
		ll num = binaryPow(a, b/2) ;	//优化 
		return num * num ;// 不直接写成return binaryPow(a, b/2, m) * binaryPow(a, b/2, m)
}

这道题是算a^b的解,其实暴力破解,运用一个for循环便能算出答案
… int t=a;
for(int i=1;i<b;i++)
{ a=ta;t=a;}
但是还有更快的方法,那就是运用递归例如当b==5时,
a5=a*(a4)
=a
(a2*a2)
=a*((aa)(a*a)
也就是求当a的b次方,b为奇数时转化为a *a^ b-1的值,如果b为偶数则可以转化为a ^ (b/2)*a^(b/2),如果递归到b=1时,则可求出a的b次方的答案,而这个方法可以提升一半的速度。这道题虽然不是很难,但是对于理解递归的思想还是非常有帮助的,递归其实就是将一个很难算的值不断的转换成一个较小的值,通过转换成一个可以简单计算的值,即可逆推出所求的值。
2 dfs例题

#include<cstdio>
#include<iostream>
#include<iomanip>
using namespace std;
int num=0,a[10001]={0},n,r;
bool b[10001]={0};
int search(int); //回溯过程
int print(); //输出方案

int main()
{
  cout<<"input n,r:";
  cin>>n>>r;
  search(1);
  cout<<"number="<<num<<endl;     //输出方案总数
}
int search(int k)
{
    int i;
    for (i=1;i<=n;i++)
     if  (!b[i]) //判断i是否可用
      {
         a[k]=i;    //保存结果
         b[i]=1;
         if (k==r) print();
            else search(k+1);
         b[i]=0; 
      }
}
int print()
{
  num++;
  for (int i=1;i<=r;i++)
    cout<<setw(3)<<a[i];
  cout<<endl; 
}

这道题要求有n个整数的集合{1,2,…,n},从中取出任意r个数进行排列(r<n),试列出所有的排列。这道题用了许多全局变量,但在c++中应该尽量减少使用全局变量,因为c++是面向对象的语言(这里不过多赘述),不过在这中算法题中,使用全局变量还是大大减少了代码重复使用。这道题的思路是,首先找第一个我们需要的数,然后找到第二个,直到找到第r个我们需要的数,然后回溯。
在这里插入图片描述

先在一条路上走完,然后返回到上一级找下一个数,直到便利完这条路所有可能,然后找其他路径的情况。这道题的思路是典型的dfs算法的思想,通过找第i个数可能的值,然后算出所有的情况,不过原理虽然不是很难,但是我想自己写出这样的代码感觉还是比较困难的。
3 bfs例题

int n;
int main()
{
    //int n;
    while(cin>>n&&n)
    cout<<bfs()<<endl;
    return 0;
}
int n;
long long bfs()
{
    queue<long long> q;
     while(!q.empty()) q.pop();
    q.push(1);
    while(!q.empty())
    {
    if(q.front()%n==0) return q.front();
         long long p=q.front();
        q.pop();
        q.push(p*10);
        q.push(p*10+1);
    }
    return 0;
 
}
 这道题要求给出一个整数n,(1 <= n <= 200)。求出任意一个它的倍数m,要求m必须只由十进制的'0'或'1'组成,这道题很罕见的使用了队列(话说做了很多acm的题了,仔细想想很少使用队列),但是在某些时候确意外的很有用,比如这道题,这道题要求出n的一个倍数m,但是要求m必须由0和1组成, 所以一个很显然m的首位必须为1,所以我们首先将1放在队列最前面,然后用一个!q.empty()来判断队列是否为空,我们通过循环来判断排在第一个数能否整除n,如果能,说明找到了答案。不能,我们则去除第一位数,并且将第一位数乘10和乘10+1来获得第二行数(全为1,0组成),第二次循环继续判断第一个数,看是否符合条件。这里贴一张图来更清晰的看出情况的变化.

在这里插入图片描述

可以看出,每一行代表着我们要遍历的情况,我们首先找出第一行,是否符合条件,如果不符合,那么就往下一行进行判断。这道题感觉如果不用队列,感觉速度会很慢,并且会很复杂。
每周总结:
本周算是本学期严格意义上acm课的最后一周,不知不觉acm已经上了12周,我在这段时间也慢慢习惯了acm的模式,感觉每周每天都需要做acm的题让我感到十分的有压迫感,而且在每一次做题的时候看不懂题时,内心也是十分的焦灼,但是在每一次靠自己ac一道题时内心也会产生出很大的喜悦,也许这就是算法题的魅力吧,虽然acm课程结束了,但是我也慢慢学会了学习的方法,在接下来的时间,我也会继续学习算法知识,并且让自己变的更强。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值