基础算法

在学习c语言时,总感觉自己学习的不过是皮毛的东西,近几日受大神的建议之下,开始学习算法。同时加以NOIP的练习,虽说我的学习是从最简单的学起的。甚至有些早已在课程中学过,但是若是看实例分析,仍是有些吃力。为了此次的学习,特地学习了基础的c++语法知识。现将我的归纳总结列出如下:(一来是日后给自己一个复习的空间,二来望各位大神指导提出我的错误理解)

一.递归
/*本例子是用来说明基础算法之递归
* 题目:汉诺塔,输入一个整数n表示有n个盘片在第一根柱子上,输出操作序列,使得用最少的操作把所有的盘子*      从a柱子转移到c柱子上
* 解题思路:当盘子的个数为n时,移动的次数为2^n-1。首先把3根柱子按顺序排成“品”字形,把所有的圆盘按从* 大到小的顺序放在柱子A上。若n为偶数,按顺时针依次摆放a,b,c;若为奇数,则按顺时针依次摆放a,c,b
* 1.按顺时针把圆盘1从现在的柱子移动到下一根柱子(即若为偶数,而圆盘1在柱子A上,则把它移动到B上
* 2.接着把另外两根非空柱子上的圆盘移动到新的柱子上;若两根柱子都非空时,移动较小的圆盘
* 3.反复进行1,2操作                                                                 */
#include <fstream>
#include <iostream>
using namespace std;
void Move(int n,char x,char y){
    cout<<"move "<<n<<" from "<<x<<" to "<<y<<endl;
}
void Hannoi(int n,char a,char b,char c){
    if(n==1)
        Move(1,a,c);
    else{
        Hannoi(n-1,a,c,b);
        Move(n,a,c);
        Hannoi(n-1,b,a,c);
    }
}
int main(){
    int n;
    scanf("%d",&n);
    Hannoi(n,'a','b','c');
    return 0;
}
/*n=3时,
Hannoi(2,a,c,b);
【Hannoi(1,a,b,c){Move(1,a,c)};Move(2,a,b);Hannoi(1,c,a,b);{Move(1,c,b)}】
Move(3,a,c);
Hannoi(2,b,a,c);
【Hannoi(1,b,c,a){Move(1,b,a)};Move(2,b,c);Hannoi(1,a,b,c);{Move(1,a,c)}】
 输出为:move 1 from a to c
    move 2 from a to b
    move 1 from c to b
    move 3 from a to c
    move 1 from b to a
    move 2 from b to c
    move 1 from a to c                                                             */

二.分治

/*本例子是用来说明基础算法之分治(基本思路是将一个规模为N的问题分解为K个规**模较小的子问题,这些子问题相互独立且原问题性质相同。
* 题目:计数问题:给定两个数a,b,计算出1在a,b出现的次数,输入两个0时程序结* 束,两个0不作为输入样例
* 解题思路:1.求出190~197之间出现的次数,然后对于0~189.190~197中1在个位* 数上只出现了一次
*          2.个位考虑完后,直接考虑197/10-1(即18)中1出现的次数,同时 * 考虑到,数字减小了,每一位的权值会增加。也就是说每一个数字出现的次数会增 * 加10倍。                                */
#include <iostream>
using namespace std;

const int N=11;
int d[N];//d[N]中存储数字0~9分别出现的次数
int value;
void deal(int n);

int main(){
    int a,b;
    while(cin>>a>>b){
        if(a==0&&b==0)break;
        if(a<b){int tmp=b;b=a;a=tmp;}//将较大的值存入a,较小值存入b
        for(int i=0;i<10;i++)
            d[i]=0;//初始化操作
        /*处理过程*/
        value=1;
        deal(a);
        value=-1;//此处value=-1是为了求出最后的答案deal(a)-deal(b)
        deal(b-1);
        /*输出结果*/
        cout<<d[1]<<endl;
    }
    return 0;
}

void deal(int n){
    if(n<0)return;
    int one,ten;//分别表示个位,十位
    one=n%10;
    n/=10;
    ten=n;
    for(int i=0;i<=one;i++)
        d[i]+=value;
//1.算出190^197个位出现1的情况;2.算出110-119十位出现1的情况
    while(ten){
        d[ten%10]+=(one+1)*value;
//1.算出190~197,十位与百位出现1的情况2.算出100-180百(千)位出现1的情况
        ten/=10;
    }
    for(int i=0;i<10;i++)
        d[i]+=value*n;
    d[0]-=value;//将第一位是0的情况排除
//1.算出1,11,21……,181个位出现1的情况;2.算出10,110十位出现1的情况
    value*=10;//权值变化,变为原来的10倍
    deal(n-1);//算出18时的情况,即0~189情况,此时权值增加到十倍
}

三.贪心

/*本例子是用来说明基础算法之递归
* 题目:A公司每次都是将连续5个月的盈或亏的总和做一次性的公布。已知所有月的 * 盈利固定为s,而亏损月的亏损固定为d
* 编写一个程序,确定MS公司是否盈利,若盈利的话,计算可能盈利的最大值。
* 输入为:两个正整数s和d。
* 输出为:若盈利的话,输出可能的盈利最大值;若亏损的话,输出Deficit
* 解题思路:首先每连续5个月中至少有哪几个月是亏损的是可以计算出来的假设5个 * 月至少亏损3个月,那么对于前五个月来说,亏损的月份必定是3、4、5月,这样才* 能减少出现更多的亏损月   */
#include <iostream>
#include <cstdio>
using namespace std;
int main(){
    int s,d;
    while(scanf("%d%d",&s,&d)!=EOF){
        int i,ans;
        for(i=1;i<=5;i++)
            if(s*(5-i)-d*i<0)
                break;
        if(i==4)
            ans=3*s-9*d;
        else
            ans=s*(12-2*i)-d*2*i;
        if(i==5||ans<0)
            printf("Deficit\n");
        else
            printf("%d\n",ans);
    }
}

/*  1   2   3   4   5   6   7   ||8   9   10  11  12
* 1                 *                     *
* 2             *   *                 *   *
* 3         *   *   *             *   *   *
* 4     *   *   *   *       *     *   *   *    *
* 5 *   *   *   *   *   *   *     *   *   *    *   *
*                                                                          */

四.枚举

/*本例子是用来说明基础算法之枚举
* 题目:输入多组数据,每组包括两行,第一行输入一个n(<100),表示小A有n根木* 根,接着一行有n个整数(<1000),表示木棍的长度(长度从小到大给出)
* 输出可以组成面积最大的直角三角形的面积,且保留三位有效数字,如果不能组成 *输出“My God!"
* 解题思路:把所有直角三角形的可能性枚举出来,利用题目中木棍的长度从大到小 * 排列,而斜边最长这一特征                                    */
#include <stdio.h>
#include <stdlib.h>
int main(){
    int i,j,k;
    double ans;
    int n;
    int len[110];
    while(scanf("%d",&n)!=EOF){
        for(i=1;i<=n;i++)
            scanf("%d",&len[i]);
        ans=-1;
        for(i=1;i<=n;i++){//枚举最短木棍
            for(j=i+1;j<=n;j++){//枚举第二长的木棍
                for(k=j+1;k<=n;k++){//枚举最长的木棍
                    if(len[i]*len[i]+len[j]*len[j]==len[k]*len[k]){//如果是直角三角形
                        if(0.5*len[i]*len[j]>ans)//取最优解
                            ans=0.5*len[i]*len[j];
                    }
                }
            }
        }
        if(ans==-1)
            printf("My God!\n");
        else
            printf("%.3lf\n",ans);
    }
    return 0;
}
以上为基础算法,看来似乎简单易懂,但其中算法的思想却不可以忽略,在以后的许多问题中都会有体现。掌握算法的核心思想确实有必要。在后面,我会更新出相应的实例。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值