小时候玩游戏,有个BOMB人的游戏,把BOMB放在一个空地上,将怪兽炸死,如图:
BOMB的威力只要不碰到墙壁,可以无限延长。那么我们应该把BOMB放哪里可以炸死最多的怪兽呢?
这个问题貌似很简单,一个一个地方试下不就知道了吗?是啊,那我们用代码来试下。
将图象转成字符,用#表示墙,用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#
#############
那我只要把所有的空地试下就知道哪里放BOMB最好了。
int main() { char a[20][20]; int i, j, sum , map, p, q = 0; int n, m, x, y; //m表示多少行字符,n表示多少列字符 scanf("%d %d", &n, &m); for(i = 0; i <= n - 1; i++) { scanf("%s", a[i]); } for (i = 0; i <= n - 1; i++) { for (j = 0; j <= m - 1; j++) { //判断当前所在位置是不是平地,是平地才可以放BOMB if(a[i][j] != '.') { continue; } //当前可以炸0个怪兽 sum = 0; x = i; y = j; //向上扩展计算消灭的怪兽数 while(a[x][y] != '#') { if(a[x][y] == 'G')sum++; x--; } x = i; y = j; //向下扩展计算消灭的怪兽数 while(a[x][y] != '#') { if(a[x][y] == 'G')sum++; x++; } x = i; y = j; //向左扩展计算消灭的怪兽数 while(a[x][y] != '#') { if(a[x][y] == 'G')sum++; y--; } x = i; y = j; //向右扩展计算消灭的怪兽数 while(a[x][y] != '#') { if(a[x][y] == 'G')sum++; y++; } //如果消灭的怪兽大于map,则更新map,并记住所在的坐标 if(sum > map) { map = sum; p = i; q = j; } } } printf("将BOMB放在(%d,%d)处,可以消灭最多%d怪兽只\n", p, q, map); getchar(); getchar(); return 0; }
打印结果为:将BOMB放在(1,11)处,可以消灭最多11怪兽只。这种算法为枚举,
好像有点不对劲啊,小人根本到不了(1,11),所以那里根本不放了BOMB。所以说我们不能将所有的空地都计算进去,需要将到不了的空地排除。这里该深度优先算法出场了(当然还有其它算法可以解决)。
走过迷宫的都知道,我们会沿一条走到头,死路时就回头,回到上一个岔路口,已经确定了一条死路,我们就走另一条路,又是死路,我们就再回到岔路口,两条都是死路了,就回到上上个岔路口,依此循环。
这个问题就像小人在走迷宫,直到所有的空地都被小人走过为此。我们用递归来实现这个逻辑:
char a[20][21]; int book[20][20];//标记某个点是否被走过 int max, mx, my, n, m; //计算当前空地可以炸死的怪兽 int getSum(int i, int j) { int sum, x, y; //当前可以炸0个怪兽 sum = 0; x = i; y = j; //向上扩展计算消灭的怪兽数 while(a[x][y] != '#') { if(a[x][y] == 'G')sum++; x--; } x = i; y = j; //向下扩展计算消灭的怪兽数 while(a[x][y] != '#') { if(a[x][y] == 'G')sum++; x++; } x = i; y = j; //向左扩展计算消灭的怪兽数 while(a[x][y] != '#') { if(a[x][y] == 'G')sum++; y--; } x = i; y = j; //向右扩展计算消灭的怪兽数 while(a[x][y] != '#') { if(a[x][y] == 'G')sum++; y++; } return sum; } void dfs(int x, int y) { //定义上下左右走动时x,y轴的变化 int next[4][2] = {{0, 1}, {0, -1}, {1, 0}, { -1, 0}}; int k, sum, tx, ty; sum = getSum(x, y); if(sum > max) { max = sum; mx = x; my = y; } for(k = 0; k <= 3; k++) { tx = x + next[k][0]; ty = y + next[k][1]; if(tx < 0 || tx > n - 1 || ty < 0 || ty > n - 1)continue; if(a[tx][ty] == '.' && book[tx][ty] == 0) { book[tx][ty] = 1;//标记走过这个空地了 dfs(tx, ty);//走向下一个空地 } } return ; } int main() { int i, startx, starty; scanf("%d %d %d %d", &n, &m, &startx, &starty); for(i = 0; i <= n - 1; i++) { scanf("%s", a[i]); } book[startx][starty] = 1; mx = startx; my = starty; max = getSum(startx, starty); dfs(startx, starty); printf("将BOMB放置在(%d,%d),最多可以消灭%d个怪兽\n", mx, my, max ); return 0; }
得到结果:将BOMB放置在(7,11),最多可以消灭10个怪兽。
我再用“栈”来实现:
char a[20][21]; //栈的节点 struct note { int x; int y; }; //获取当前空地能消灭的怪兽数 int getSum(int i, int j) { int sum, x, y; //当前可以炸0个怪兽 sum = 0; x = i; y = j; //向上扩展计算消灭的怪兽数 while(a[x][y] != '#') { if(a[x][y] == 'G')sum++; x--; } x = i; y = j; //向下扩展计算消灭的怪兽数 while(a[x][y] != '#') { if(a[x][y] == 'G')sum++; x++; } x = i; y = j; //向左扩展计算消灭的怪兽数 while(a[x][y] != '#') { if(a[x][y] == 'G')sum++; y--; } x = i; y = j; //向右扩展计算消灭的怪兽数 while(a[x][y] != '#') { if(a[x][y] == 'G')sum++; y++; } return sum; } int main() { //初始化一个栈 struct note que[401]; int book[20][20]; int n,m,mx,my,max,top=0, i, startx, starty; scanf("%d %d %d %d", &n, &m, &startx, &starty); for(i = 0; i <= n - 1; i++) { scanf("%s", a[i]); } book[startx][starty] = 1; mx = startx; my = starty; //当起始点加入到栈中 top++; que[top].x = startx; que[top].y = starty; max = getSum(startx, starty); int next[4][2] = {{0, 1}, {0, -1}, {1, 0}, { -1, 0}}; int k, sum, tx, ty; //直到栈空了 while(top != 0) { sum = getSum(que[top].x, que[top].y); if(sum > max) { max = sum; mx = que[top].x; my = que[top].y; } for(k = 0; k <= 3; k++) { tx = que[top].x + next[k][0]; ty = que[top].y + next[k][1]; if(tx < 0 || tx > n - 1 || ty < 0 || ty > n - 1)continue; if(a[tx][ty] == '.' && book[tx][ty] == 0) { book[tx][ty] = 1; top++; que[top].x = tx; que[top].y = ty; break; } //这句很关键,一个空地上下左右都试走过后,将此空地移除栈 if(k == 3)top--; } } printf("将BOMB放置在(%d,%d),最多可以消灭%d个怪兽\n", mx, my, max ); return 0; }
得到的结果是一样的。
这套算法应用十分广泛,可以解决很多问题。作为一名码农还是非常有必要学习一下的,与这对应的还有“广度优先搜索算法”.