算法基础2 —— OJ入门以及暴力枚举

常见的OJ术语
  • Accepted (AC)—— 成功过题
  • Wrong Answer (WA) —— 输出结果错,一般是算法有问题,需要重新考虑思路或者其他
  • Runtime Error (RE) —— 运行时错误,一般是程序在运行期间执行了非法的操作(大部分情况下是由于数组的原因:非法操作、越界)
  • Time Limit Exceeded (TLE) —— 程序运行的时间超出了题目的时间限制
  • Memory Limit Exceeded (MLE) —— 程序运行的内存超出了题目的内存限制
  • Compilation Error (CE) —— 语法有问题,编译器无法编译
  • Presentation Error (PE) —— 程序貌似输出了正确的结果,但是这个结果的格式有问题。出现PE说明解题思路基本上没问题了,可能是输出多了或者少了空格、换行符等等
  • Queuing —— OJ无法在第一时间给所有提交以评判结果,后面提交的程序将暂时处于排队状态等待OJ的评判
  • Compiling —— 提交的代码正在被编译
  • Running —— 程序正在运行
  • Judging —— OJ正在判题

暴力法

—— 暴力出奇迹 ~ 直接看例题
暴力法即暴力枚举(一般使用for循环来实现),指的是设计一个程序,可以找出当前问题所有可能的结果,然后让计算机筛选出其中正确的答案
暴力枚举的缺点:时间复杂度高

例1 解密奥数难题(选自《啊哈算法》)

将数字1~9分别填入9个方框中,每个数字只能使用一次使得等式成立。例如:173+286=459
在这里插入图片描述

思路
使用九层for循环枚举所有的位置,每个位置上定义一个变量枚举数字1 ~ 9

代码如下:

#include <iostream> 
#include <cstdio>

using namespace std;

int main()
{
    int count = 0;//计数器,记录所有正确的答案的数量
    for (int a = 1;a <= 9;a++) 
     for (int b = 1;b <= 9;b++)
      for (int c = 1;c <= 9;c++)
       for (int d = 1;d <= 9;d++)
        for (int e = 1;e <= 9;e++)
         for (int f = 1;f <= 9;f++)
          for (int g = 1;g <= 9;g++)
           for (int h = 1;h <= 9;h++)
            for (int i = 1;i <= 9;i++)
            {
                //保证填入的数字两两互不相等
                //如果只判断第一个数与其他数不等,那么可能会出现12****2的情况(即第二个数字可能会与其他数字相同)
                if (a != b && a != c && a != d && a != e && a != f && a != g && a != h && a != i && 
                    b != c && b != d && b != e && b != f && b != g && b != h && b != i && 
                    c != d && c != e && c != f && c != g && c != h && c != i &&
                    d != e && d != f && d != g && d != h && d != i && 
                    e != f && e != g && e != h && e != i &&
                    f != g && f != h && f != i &&
                    g != h && g != i &&
                    h != i)
                    if (a*100+b*10+c + d*100+e*10+f == h*100+g*10+i)
                    {
                        count ++;
                        printf("%d%d%d + %d%d%d = %d%d%d\n",a,b,c,d,e,f,g,h,i);
                    }
            }
    printf("%d",count / 2);//搜索完所有的结果之后输出满足条件的结果总数:168。count之所以要除以2,是因为173+286=459以及286+173=459计算机会将其当成两组解
    return 0;
}
例2 全排列(选自《啊哈算法》)

编程求1,2,3三个数字组成的全排列
全排列可以用递归实现,三个数字的全排列写起来最简单的方法当然要数暴力解法~
当然本题还有其他解法:

  • next_permutation

  • DFS(深度优先搜索)

思路
使用三层for循环枚举所有的位置,每个位置上定义一个变量枚举数字1 ~ 3

#include <iostream> 
#include <cstdio>

using namespace std;

int main()
{
	//三个for循环枚举三个位置的数字
    for (int i = 1;i <= 3;i++)//枚举第1个位置上的三个数字
     for (int j = 1;j <= 3;j++)//枚举第2个位置上的三个数字
      for (int k = 1;k <= 3;k++)//枚举第3个位置上的三个数字
       if (i != j && i != k && j != k)
        //数字两两互不相等即可输出
        printf("%d%d%d\n",i,j,k);
    return 0;
}
总结例1和例2的思路:

例1思路:对每个方框可以填的数进行枚举,只要满足每个位置的数字两两互不相等,并且组成的数字满足等式,那么即可输出答案。
例2思路:使用for循环枚举三个位置,每个位置枚举三个数字,当三个位置的数字两两互不相等时,那么即可输出结果。

炸弹人游戏(搜索算法入门,选自《啊哈算法》)

最近小S迷恋上一款“炸弹人”游戏,在过关关卡中,她要在空地放置炸弹,使得被消灭的敌人最多,
现在,小S请你帮她编写一个程序,看看放于何处,消灭掉的敌人最多。并求出最多可以消灭多少敌人。

本题默认:

  • 在图中,(1,3),(2,3),(3,3),(3,1)等位置表示空地,可以放置炸弹
  • 一个炸弹可以消灭与该炸弹在同一行及同一列上的所有敌人(例:如果将炸弹放置在(1,3)的位置,那么该炸弹一共可以消灭5个敌人)
  • 炸弹不能穿墙消灭敌人(例:如果将炸弹放置在(1,3)的位置,那么炸弹不能穿过(1,7)处的墙壁消灭(1,8),(1,10),(1,11)处的敌人)

在这里插入图片描述
如果

  • 用’#'表示墙壁
  • 用’.'表示空地
  • 用’G’表示敌人

可将地图抽象为:

#############
#GG.GGG#GGG.#
###.#G#G#G#G#
#.......#..G#
#G#.###.#G#G#
#GG.GGG.#.GG#
#G#.#G#.#.###
##G...G.....#
#G#.#G###.#G#
#...G#GGG.GG#
#G#.#G#G#.#G#
#GG.GGG#G.GG#
#############
思路:

枚举每一个可以防止炸弹的位置,分别向上下左右四个方向进行搜索,计算可以伤害到的敌人总数。选择其中伤害敌人最多的位置即可。

实现本题的代码如下:

#include <iostream> 
#include <cstdio>

using namespace std;

int main()
{
    char a[20][20];//定义一个地图
    int m,n;
    int count;//记录消灭敌人的数量
    int p,q;//可以消灭最多的敌人的点
    int gmax = -1;//炸弹可以消灭的最多敌人数,每遍历一遍地图即可更新gmax且gmax最少为0
    scanf("%d%d",&m,&n);//m表示地图的行数,n表示地图的列数
    
    for (int i = 0;i < m;i++) scanf("%s",a[i]);//读入地图每行的数据
    
    for (int i = 0;i < m;i++)//遍历地图
     for (int j = 0;j < n;j++)
        if (a[i][j] == '.')//如果当前位置是空地
        {
            count = 0;//计数器,记录消灭的敌人的数量(每次遍历地图都需要清空上一次的count)
            int x,y;//xy分别表示行坐标和列坐标(可以移动)
            
            //向上试探该炸弹可以消灭多少个敌人
            x = i,y = j;
            while (a[x][y] != '#')//炸弹不撞墙
            {
            	x--;
                if (a[x][y] == 'G') count ++; 
            }
            
            //向下试探炸弹可以消灭多少个敌人
            x = i,y = j;//点(x,y)需要回归到之前的位置
            while (a[x][y] != '#')
            {
                x++;
                if (a[x][y] == 'G') count ++;
            }
            
            //向左试探炸弹可以消灭多少个敌人
            x = i,y = j;
            while (a[x][y] != '#')
            {
            	y--;
                if (a[x][y] == 'G') count ++;
            }
            
            //向右试探炸弹可以消灭多少个敌人
            x = i,y = j;
            while (a[x][y] != '#')
            {
            	y++;
                if (a[x][y] == 'G') count ++;
            }
            
            if (gmax < count) 
            {
                p = i;//在点(p,q)放置炸弹可以消灭最多的敌人
                q = j;
                gmax = count;//更新可以消灭的最多敌人数量
            }
        }
    
    printf("(%d,%d)\n",p,q);//输出可以消灭最多敌人的炸弹点:(9,9)
    printf("%d\n",gmax);//输出可以消灭的最多的敌人:8
        
    return 0;
}

总结该题的搜索模板:

While(a[x][y]!=‘#’)//在不撞墙的搜索前提下
{
	 x++或x--或y++或y--;//向下上右左四个方向搜索敌人
     if(a[x][y]==‘G’)//只要遇见敌人
              count ++;//数量加1
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值