poj-3009

来源:互联网 发布:天猫双十一直播数据 编辑:程序博客网 时间:2024/05/17 04:30
//376K172MSG++#include <stdio.h>#include <string.h>#define MAX 30int W;int H;int board[MAX][MAX];int Sx;int Sy;int Gx;int Gy;#define INF 99999int dfs(int curX, int curY, int throwTime) {int minThrow = INF;if (throwTime > 10) {return minThrow;} // first check if blocked immdiatelyif (curY + 1 <= H-1 && board[curX][curY + 1] != 1) {// upint upNearest = -1;for (int i = curY+1 ;i <= H-1; i++) {if (board[curX][i] == 1) {// the nearest block is in (curX, i)// the ball stop and (curX, i-1)upNearest = i - 1;break;}}if (upNearest == -1) {if (curX == Gx && curY < Gy) { // can reach goalif (throwTime < 10) {return throwTime + 1;}}} else {if (upNearest >= Gy && curX == Gx && curY < Gy) { // can reach goalif (throwTime < 10) {return throwTime + 1;}}}if (upNearest > -1) { // if there is up blockboard[curX][upNearest+1] = 0; // block is brokenint res = dfs(curX, upNearest, throwTime+1);minThrow = minThrow < res ? minThrow : res;board[curX][upNearest+1] = 1; // restore the block for other direction }}// down,//first check if blocked immdiatelyif (curY-1 >=0 && board[curX][curY-1] != 1) {int downNearest = -1;for (int i = curY-1 ;i >= 0; i--) {if (board[curX][i] == 1) {// the nearest block is in (curX, i)// the ball stop and (curX, i-1)downNearest = i + 1;break;}}if (downNearest == -1) {if (curX == Gx && curY > Gy) { // can reach goalif (throwTime < 10) {return throwTime + 1;}}} else {if (downNearest <= Gy && curX == Gx && curY > Gy) { // can reach goalif (throwTime < 10) {return throwTime + 1;}}}if (downNearest > -1) { // if there is up blockboard[curX][downNearest-1] = 0; // block is brokenint res = dfs(curX, downNearest,throwTime+1);minThrow = minThrow < res ? minThrow : res;board[curX][downNearest-1] = 1; // restore the block for other direction }}// left//first check if blocked immdiatelyif (curX-1 >= 0 && board[curX-1][curY] != 1) {int leftNearest = -1;for (int i = curX-1 ;i >= 0; i--) {if (board[i][curY] == 1) {// the nearest block is in (curX, i)// the ball stop and (curX, i-1)leftNearest = i + 1;break;}}if (leftNearest == -1) {if (curY == Gy && curX > Gx) { // can reach goalif (throwTime < 10) {return throwTime + 1;}}} else {if (leftNearest <= Gx && curY == Gy && curX > Gx) { // can reach goalif (throwTime < 10) {return throwTime + 1;}}}if (leftNearest > -1) { // if there is up blockboard[leftNearest-1][curY] = 0; // block is brokenint res = dfs(leftNearest, curY,throwTime+1);minThrow = minThrow < res ? minThrow : res;board[leftNearest-1][curY] = 1; // restore the block for other direction }}// right//first check if blocked immdiatelyif (curX + 1 <= W-1 && board[curX+1][curY] != 1) {int rightNearest = -1;for (int i = curX+1 ;i <= W-1; i++) {if (board[i][curY] == 1) {// the nearest block is in (curX, i)// the ball stop and (curX, i-1)rightNearest = i - 1;break;}}if (rightNearest == -1) {if (curY == Gy && curX < Gx) { // can reach goalif (throwTime < 10) {return throwTime + 1;}}} else {// printf("%d %d %d\n", Gx, curX, rightNearest);if (rightNearest >= Gx && curY == Gy && curX < Gx) { // can reach goalif (throwTime < 10) {return throwTime + 1;}}}if (rightNearest > -1) { // if there is up blockboard[rightNearest+1][curY] = 0; // block is brokenint res = dfs(rightNearest, curY,throwTime+1);minThrow = minThrow < res ? minThrow : res;board[rightNearest+1][curY] = 1; // restore the block for other direction }}return minThrow;}void solve() {int minThrow = dfs(Sx, Sy, 0);if (minThrow == INF) {printf("-1\n");} else {printf("%d\n", minThrow);}}int main() {while(1) {scanf("%d %d", &W, &H);if (W == 0 && H == 0) {return 1;}memset(board, 0, sizeof(board));for (int i = 0; i < H; i++) {for (int j = 0; j < W; j++) {int tmp;scanf("%d", &tmp);board[j][i] = tmp;if (tmp == 2) {Sx = j;Sy = i;// printf("S %d %d\n", Sx, Sy);} else if (tmp == 3) {Gx = j;Gy = i;// printf("G %d %d\n", Gx, Gy);}}}solve();}}

中规中矩的DFS题(用BFS应该也行吧,不过没想好如何保存board的状态,20*20 == 400 , 就算是状态压缩也没有这么大的整型数)。

题目还很贴心的告知了DFS最大的递归次数是12,可以剪枝来提高效率。

有一个比较细的规则,如果球的周围一格有block,那么就不能向该方向throw了,先做此判定,如果能throw,

再看在throw的一行/列上是否能有block将其停住,

如果没有,还要考虑虽然没有block将其停住,但是能经过终点将其停住的情况, 以及有block,但是throw先经过终点的情况。

如果有,并且没有经过终点,就从此block的临近一格(题目规定)开始新的BFS,同时将此block清掉,在此轮DFS返回以后,再恢复现场,

将block重新设上,就这样处理四个方向,得到四个方向能得到的最小throw次数(INF代表不能达到终点),

另外,本题也没有用到DFSvisitedFlag,应该是因为每次都会消去一格block,并且规定了最大剪枝,因此DFSvistedFlag可以不用(并且也没有合适的实现方式,

board的状态是没法用数组保存的)。

0 0