104北市賽 搶救雷恩大兵

出處:104北市賽 http://tioj.infor.org/problems/1034

題目:https://docs.google.com/viewer?a=v&pid=sites&srcid=ZGVmYXVsdGRvbWFpbnx6c2dpdGl0aXR8Z3g6YjMwYzE4OTE3MDliOWQz

解題策略:使用BFS分別由起點與終點往死光彈走,找出累加最小值

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132

#include <cstdio>#include <cstring>#include <queue>#define NUM 21using namespace std; int s[NUM][NUM], t[NUM][NUM], map[NUM][NUM],ans[NUM][NUM][NUM][NUM]; int gor[4] = { 1,0,-1,0 }; //四個方向 int goc[4] = { 0,1,0,-1 }; //四個方向typedef struct _point { int r; int c; int w; }Point; struct cmp { bool operator()(const Point &a, const Point &b) { return a.w > b.w; } }; priority_queue <Point,vector<Point>,cmp > myq; int bound(int r, int c, int N) { if (((r>0) && (r <= N)) && ((c>0) && (c <= N))) return 1; else return 0; } int abso(int x, int y) { if (x>y) return x - y; else return y - x; } void bfs0(int r, int c, int i, int j, int N) {//(r,c)出發在(i,j)使用死光彈,所獲得到每一點的最小值 int tmp = map[i][j]; Point myp, nowp, nextp; memset(s, 0x7f, sizeof(s)); map[i][j] = 0; s[r][c] = map[r][c]; myp.r = r; myp.c = c; myp.w = s[r][c]; myq.push(myp); //加入queue中 while (myq.size()>0) { nowp = myq.top(); //取出queue的第一個 myq.pop(); //將queue的第一個刪除 for (int k = 0; k<4; k++) { //四個方向加入queue nextp.r = nowp.r + gor[k]; nextp.c = nowp.c + goc[k]; if ((bound(nextp.r, nextp.c, N)) && (s[nextp.r][nextp.c]>s[nowp.r][nowp.c] + map[nextp.r][nextp.c])) { //在地圖內,且發現比較小 s[nextp.r][nextp.c] = s[nowp.r][nowp.c] + map[nextp.r][nextp.c]; if (nextp.r == i && nextp.c == j) {//到達目的地就結束,清空Queue while (myq.size() > 0) { myq.pop(); } break; } myp.r = nextp.r; myp.c = nextp.c; myp.w = s[myp.r][myp.c]; myq.push(myp); //加入queue } } } map[i][j] = tmp; ans[r][c][i][j] = s[i][j]; } void bfs1(int r, int c, int i, int j, int N) {//(r,c)出發在(i,j)使用死光彈,所獲得到每一點的最小值 int tmp = map[i][j]; Point myp, nowp, nextp; memset(t, 0x7f, sizeof(t)); map[i][j] = 0; t[r][c] = map[r][c]; myp.r = r; myp.c = c; myp.w = t[r][c]; myq.push(myp); //加入queue中 while (myq.size()>0) { nowp = myq.top(); //取出queue的第一個 myq.pop(); //將queue的第一個刪除 for (int k = 0; k<4; k++) { //四個方向加入queue nextp.r = nowp.r + gor[k]; nextp.c = nowp.c + goc[k]; if ((bound(nextp.r, nextp.c, N)) && (t[nextp.r][nextp.c]>t[nowp.r][nowp.c] + map[nextp.r][nextp.c])) { //在地圖內,且發現比較小 t[nextp.r][nextp.c] = t[nowp.r][nowp.c] + map[nextp.r][nextp.c]; if (nextp.r == i && nextp.c == j) { while (myq.size() > 0) { myq.pop(); } break; } myp.r = nextp.r; myp.c = nextp.c; myp.w = t[myp.r][myp.c]; myq.push(myp); //加入queue } } } map[i][j] = tmp; ans[r][c][i][j] = t[i][j]; } int main() { int N, q, r0, c0, r1, c1, min, max, result; Point myp, nextp; while (scanf("%d", &N) != EOF) { min = 1001; max = 0; memset(ans,-1,sizeof(ans)); for (int i = 1; i <= N; i++) { for (int j = 1; j <= N; j++) { scanf("%d", &map[i][j]); if (min>map[i][j]) min = map[i][j]; if (max<map[i][j]) max = map[i][j]; } } scanf("%d", &q); for (int i = 0; i<q; i++) { scanf("%d %d %d %d", &r0, &c0, &r1, &c1); if (min == max) printf("%d\n", abso(r0, r1)*min + abso(c0, c1)*min);//地圖每一個點值相同 else{ result = 1000000; for (int i = 1; i<=N; i++) {//要在(i,j)使用死光彈 for (int j = 1; j<=N; j++) { //if (map[i][j] != min) { //有可能起點到終點的長方形區塊都是min if (ans[r0][c0][i][j] == -1) bfs0(r0, c0, i, j, N); if (ans[r1][c1][i][j] == -1) bfs1(r1, c1, i, j, N); if (result > (ans[r0][c0][i][j] + ans[r1][c1][i][j])) result = ans[r0][c0][i][j] + ans[r1][c1][i][j]; //} } } printf("%d\n", result); } } } return 0; }