常见的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
}