基础算法

枚举

例题:公鸡5文钱一只,母鸡3文钱一只,小鸡3只一文钱,用100文钱买100只鸡,其中公鸡,母鸡,小鸡都必须要有,问公鸡,母鸡,小鸡要买多少只刚好凑足100文钱?

由题意可得方程式:
5x+3y+1/3z = 100
x+y+z = 100
(100>=x,y,z>=0,z%3==0)
代码:

#include <stdio.h>

int main()
{
    int i, j, k;

    printf("百元买百鸡的问题所有可能的解如下:\n");

    for( i=0; i <= 100; i++ )
        for( j=0; j <= 100; j++ )
            for( k=0; k <= 100; k++ )
            {
                if( 5*i+3*j+k/3==100 && k%3==0 && i+j+k==100 )
                {
                    printf("公鸡 %2d 只,母鸡 %2d 只,小鸡 %2d 只\n", i, j, k);
                }
            }

    return 0;
}

这种方法需要枚举 101^3 次

然而我们可以根据已知条件进行代码的优化,减少枚举的次数:
三种鸡的和是固定的,我们只需要枚举两种鸡想(x,y),第三种鸡就可以根据约束条件求得(z=100-x-y)
这样就缩小了枚举范围。
另外我们根据方程特点,可以消去一个未知数,可得:
4x+7y=100;
x+y+z=100;
x,y,z>=0,z%3==0,x<=25;
优化后代码可得:

#include <stdio.h>

int main()
{
    int x, y, z;

    printf("百元买百鸡的问题所有可能的解如下:\n");

    for (x = 0; x <= 25; x++)
    {
        y = 100 - 4 * x;
        if (y % 7 == 0 && y >= 0)
        {
            y /= 7;
            z = 100 - x - y;
            if(z%3==0&&3*x+5*y+z/3==100)
                printf("公鸡 %2d 只,母鸡 %2d 只,小鸡 %2d 只\n",x,y,z);
        }
    }
    return 0;
}

优化之后只需枚举25次
所以能不用枚举就不用枚举!即使真的需要用枚举也要尽量优化!

递推

递推算法分为顺推和逆推两种

顺推
例:斐波那契数列

F(1)=1,F(2)=1, F(n)=F(n - 1)+F(n - 2)

逆推:
例:银行存款,年利息是0.03,若要在n年后连本带息取出n元,至少要存多少钱。

太简单就不上代码了。

贪心

题目描述 https://www.luogu.com.cn/problem/P1090
在一个果园里,多多已经将所有的果子打了下来,而且按果子的不同种类分成了不同的堆。多多决定把所有的果子合成一堆。

每一次合并,多多可以把两堆果子合并到一起,消耗的体力等于两堆果子的重量之和。可以看出,所有的果子经过 n-1n−1 次合并之后, 就只剩下一堆了。多多在合并果子时总共消耗的体力等于每次合并所耗体力之和。

因为还要花大力气把这些果子搬回家,所以多多在合并果子时要尽可能地节省体力。假定每个果子重量都为 11 ,并且已知果子的种类 数和每种果子的数目,你的任务是设计出合并的次序方案,使多多耗费的体力最少,并输出这个最小的体力耗费值。

例如有 33 种果子,数目依次为 11 , 22 , 99 。可以先将 11 、 22 堆合并,新堆数目为 33 ,耗费体力为 33 。接着,将新堆与原先的第三堆合并,又得到新的堆,数目为 1212 ,耗费体力为 1212 。所以多多总共耗费体力 =3+12=15=3+12=15 。可以证明 1515 为最小的体力耗费值。

输入格式
共两行。
第一行是一个整数 (1≤n≤10000) ,表示果子的种类数。

第二行包含 n 个整数,用空格分隔,第 i 个整数 ai(1≤ai≤20000) 是第i种果子的数目。

输出格式
一个整数,也就是最小的体力耗费值。输入数据保证这个值小于 2^31
输入
3
1 2 9
输出
15
说明/提示
对于30%的数据,保证有n≤1000:

对于50%的数据,保证有n≤5000;

对于全部的数据,保证有n≤10000。

#include <iostream>
#include <algorithm>
using namespace std;

int a[10005];

int main()
{
    int n, i, j;
    cin >> n;
    for (i = 1; i <= n; i++)
    {
        cin >> a[i];
    }
    sort(a+1, a + n+1);
    int ans = 0, sum;
    for (i = 1; i <= n - 1; i++)
    {
        sum = a[i] + a[i + 1];
        for (j = i + 1; j <= n-1; j++)
        {
            a[j] = a[j + 1];
            if (a[j] > sum)
            {
                a[j] = sum;
                break;
            }
        }
        if (j == n)
            a[n] = sum;
        ans += sum;
    }
    cout << ans << endl;
    return 0;
}

递归

斐波那契数列(最简单的递归)
F(1)=1,F(2)=1, F(n)=F(n - 1)+F(n - 2)

int F(int n)
{
    if (n <= 2)
        return 1;
    return F(n - 1) + f(n - 2);
}

分治

分而治之。
在n个元素中找出最大元素和最小元素。(使用了递归的方式)

void maxandmin(int a[], int i, int j, int& max, int& min)
{
    if (i == j) 
    {
        max = min = a[i];
        return;
    }
    if (j - 1 == i)
    {
        max = a[i] > a[j] ? a[i] : a[j];
        min = a[i] < a[j] ? a[i] : a[j];
        return;
    }
    int mid, max1, max2, min1, min2;
    mid = (i + j) / 2;//把n个元素分为a1,a2两组
    maxandmin(a, i, mid, max1, max2);
    maxandmin(a, mid + 1, j, max2, min2);
    max = max1 > max2 ? max1 : max2;//分别将这两组的最大最小值相比较
    min = max1 < max2 ? max1 : max2;
}

其实就是如果a1和a2中的元素多于两个,则再继续分为两个子集,直至子集中至多有两个元素为止。

构造

根据题意生成符合要求的解

例:输出n个以空格分隔的AC。

for(int i=0;i<n;i++)
{
    printf("AC ");
}
printf("AC\n");

复杂的构造往往需要用到其他知识,再次先不做讲解。

模拟

https://www.luogu.com.cn/problem/P1067

题目描述
一元nn次多项式可用如下的表达式表示:

在这里插入图片描述

其中,aix^i 称为i次项,ai称为i次项的系数。给出一个一元多项式各项的次数和系数,请按照如下规定的格式要求输出该多项式:

多项式中自变量为xx,从左到右按照次数递减顺序给出多项式。

多项式中只包含系数不为00的项。

如果多项式nn次项系数为正,则多项式开头不出现“+”号,如果多项式nn次项系数为负,则多项式以“-”号开头。

对于不是最高次的项,以“+”号或者“-”号连接此项与前一项,分别表示此项系数为正或者系数为负。紧跟一个正整数,表示此项系数的绝对值(如果一个高于00次的项,其系数的绝对值为11,则无需输出 11)。如果xx的指数大于11,则接下来紧跟的指数部分的形式为“x^bx
b
”,其中 bb为 xx的指数;如果 xx的指数为11,则接下来紧跟的指数部分形式为“xx”;如果 xx 的指数为00,则仅需输出系数即可。

多项式中,多项式的开头、结尾不含多余的空格。

输入格式
输入共有 22 行

第一行11 个整数,nn,表示一元多项式的次数。

第二行有 n+1n+1个整数,其中第ii个整数表示第n-i+1n−i+1 次项的系数,每两个整数之间用空格隔开。

输出格式
输出共 11 行,按题目所述格式输出多项式。

输入输出样例
输入
5
100 -1 1 -3 0 10
输出
100x5-x4+x3-3x2+10
输入
3
-50 0 0 1
输出
-50x^3+1

NOIP 2009 普及组 第一题

对于100%数据,0 ≤n≤100,−100≤系数≤100

#include <iostream>
#include <cmath>
using namespace std;

int main()
{
    int n,i,a;
    cin >> n;//多项式的次数
    for (i = n; i>=0; i--)
    {
        cin >>a;
        if (a)//判断a是否为0
        {
            if (i != n && a > 0)//第一项不用输出+,且只有a为正数时需要输出+号
                cout << "+";
            if (abs(a) > 1 || i == 0)//当a不为1或-1时输出a
                cout << a;
            if (a == -1 && i)//当a为-1且i不为0时输出-
                cout << "-";
            if (i > 1)//两次及两次以上输出指数
                cout << "x^" << i;
            if (i == 1)//一次项
                cout << "x";
        }
    }
    return 0;
}

排序

在这里插入图片描述

二分查找

int search(int a[], int n, int target)
{
    int m, l = 0, r = n - 1;
    while (l < r)
    {
        m = l + (r - l) / 2;
        if (a[m] == target)
            return m;
        if (a[m] < target)
        {
            l = m + 1;
        }
        else
        {
            r = m - 1;
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值