哈尔滨学院夏令营day5:递归+分治+二分+STL

递归

是间接和直接调用自己的算法。
递归三要素:
1.递归主题
2.递归边界
3.递归参数:每次递归发生变化的值,有时为了输入方便,递归的参数会有一部分参数没有发生变化。
每次调用递归就会减小问题规模,递归次数达到一定程度,问题规模就会足够小,小到可以直接求出答案。
举例:
求斐波那契数列前21项,存在数组里。
迭代写法:

void getf1()
{
    f[0]=f[1]=1;
    for(int i=2;i<=20;i++)
    {
        f[i]=f[i-1]+f[i-2];
    }
}

递归写法:

void getf2(int x)
{
   if(x==1||x==0)
    return f[x]=1;
   return f[x]=getf2(x-1)+getf2(x-2);
}

理解汉诺塔问题
在这里插入图片描述
int i=1;//记录步数
void move(int n,char a,char c)//显示移动路径
{
printf(“第%d步:把第%d个盘子%c—>%c\n”,i++,n,a,c);
}
void Hanoi(int n,char a,char b,char c)//汉诺塔递归算法
{
if(n==1) move(n,a,c);//如果只有一个盘子则直接从A柱移到C柱
else
{
Hanoi(n-1,a,c,b);//把A柱n-1个盘子移到B柱
move(n,a,c);//把最后一个盘子从A柱移到C柱
Hanoi(n-1,b,a,c);//把B柱n-1个盘子移到C柱
}
}
int main()
{
int num;
scanf("%d",&num);//输入盘子的个数
Hanoi(num,‘A’,‘B’,‘C’);
return 0;
}

poj 2755神奇的口袋
描述
有一个神奇的口袋,总的容积是40,用这个口袋可以变出一些物品,这些物品的总体积必须是40。John现在有n个想要得到的物品,每个物品的体积分别是a1,a2……an。John可以从这些物品中选择一些,如果选出的物体的总体积是40,那么利用这个神奇的口袋,John就可以得到这些物品。现在的问题是,John有多少种不同的选择物品的方式。
输入
输入的第一行是正整数n (1 <= n <= 20),表示不同的物品的数目。接下来的n行,每行有一个1到40之间的正整数,分别给出a1,a2……an的值。
输出
输出不同的选择物品的方式的数目。
样例输入
3
20
20
20
样例输出
3

解题思路:
1.设fun(a1,a2…an,40)为a1,a2…an凑出40的方法数。
考虑凑数的方法分为两类:

有a1 和没有a1,则可以得
fun(a1,…an,40) = fun(a2…an,40-a1) //有a1

  • fun(a2…an,40) ;//没a1
    我们把a1…an所有整数放到一个数组a中,n表示数组中
    整数的个数,i表示从第i个整数开始凑数,sum,表示要凑出
    的整数,则可得公式
    fun(a,n,i,sum) = fun(a,n,i+1,sum-a[i])//用到a[i]
  • f(a,n,i+1,sum) ;//不用a[i]
    2.递归出口说明
    如果sum等于0,说明前面已经找到一种成功的组合方式,返回1,否则,就是sum不等于0
    如果i等于n,说明没有可选的数来完成这一组和方式,返回0,如果sum<0,说明刚刚尝试的组合凑不出要组合的数,所以返回0
    int a[21] ;
    int n ;
    int fun(int i,int sum)
    {
    if(sum等于0)
    return 1 ;
    if(i等于n||sum<0) return 0 ;
    return fun(i+1,sum-a[i]) + fun(i+1,sum) ;
    }
    int main()
    {
    int i,t;
    cin>>n ;
    for(i=0;i<n;i++)
    cin>>a[i] ;
    t = fun(0,40);
    cout<<t<<endl;
    return 0 ;
    }
    整数划分
    整数划分问题是算法中的一个经典命题之一,有关这个问题的讲述在讲解到递归时基本都将涉及。所谓整数划分,是指把一个正整数n写成如下形式:
    n=m1+m2+…+mi,其中1<=mi<=n,则称{m1,m2,…,mi}为n的一个划分。如果{m1,m2,…,mi}最大值不超过m,即max(m1,m2,…,mi)<=m,则称它属于n的一个m划分。这里我们记n的m划分的个数为f(n,m)。例如n=4时,有{4},{3,1},{2,2},{2,1,1},{1,1,1,1}这样的5个划分则f(n,4)=5。下面将用递归法求f(n,m):
    a)当等于1时,不论m何值,都只有一种划分{1};
    b)当m等于1时,不论n何值,都只有一种划分{1,1,…,1};
    c)当n等于m时,
    分划分中包含n时只有一种;
    当划分中不包含n即最大值小于m时有f(n,m-1)种;
    故f(n,n)=1+f(n,n-1);
    d)当n<m时,类似f(n,n)
    e)当n>m,这是最一般情况,
    若划分中包含m,即{{x1,x2,…,xi},m},x1+x2+…+xi=n-m,则f(n,m)=f(n-m,m);
    若划分中不包含m,即划分中值都比m小,f(n,m)=f(n,m-1)
    故总数 f(n, m) = f(n-m, m)+f(n,m-1)
    则递归模型:f(n,m)=1 when n等于1 or m等于01
    f(n,m)=f(n,n) when m>n
    f(n,m)=1+f(n,m-1) when m等于n
    f(n,m)=f(n-m,m)+f(n,m-1) when m<n
    int splitint(int n,int m)
    {
    if(n= =1||m= =1)return 1;
    if(n<m)return splitint(n,n);
    else if(n==m)return (1+splitint(n,m-1));
    else return(splitint(n-m,m)+splitint(n,m-1));
    }

分治

概念
把一个任务,分成形式和原任务相同,但规模更小的 几个部分任务(通常是两个部分),分别完成,或只 需要选一部完成。然后再处理完成后的这一个或几个 部分的结果,实现整个任务的完成。
典型应用:归并排序、快排
在day2-1有归并以及快排代码。

二分

猜一个范围内的数。
在包含size个元素的、从小到大排序的int数组a里查找元素 p,如果找到,则返回元素下标,如果找不到,则返回-1。要求复杂度O(log(n))

int BinarySearch(int a[],int size,int p)
{
    int L = 0; //查找区间的左端点
    int R = size - 1; //查找区间的右端点
    while( L <= R) //如果查找区间不为空就继续查找
    {
        int mid = L+(R-L)/2; //取查找区间正中元素的下标
        if( p == a[mid] )
            return mid;
        else if( p > a[mid])
            L = mid + 1; //设置新的查找区间的左端点
        else
            R = mid - 1; //设置新的查找区间的右端点

    }
    return -1;
}//复杂度O(log(n))

为了防止 (L+R)过大溢出:
int mid = L+(R-L)/2;

STL

直接给个知识挺全的网站吧
STL详解

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值