我用了dfs, 但是范围太大, 剪枝什么的不奏效。。。
TLE代码:
#include
#include
#include
#define INF (1<<30)-1
using namespace std;
const int maxn = 100+10;
int N, M, maxT, T[maxn][maxn], maxP;
int B_T[maxn][maxn]; //从起点开始到达每一个点的最少时间
int dirx[] = {0, 0, -1, 1};
int diry[] = {1, -1, 0, 0};
char G[maxn][maxn];
struct node{
int x, y, t;
node() {}
node(int _x, int _y) {
x = _x; y = _y;
}
}P[maxn*maxn], EP[maxn*maxn];
int abs(int x) {
return x >= 0 ? x : -x;
}
void Print() {
printf("It takes %d seconds to reach the target position, let me show you the way.\n", maxT);
int cnt = 0;
for(int i = 0; i < maxP; i++) {
if(i) printf("%ds:(%d,%d)->(%d,%d)\n", ++cnt, EP[i-1].x, EP[i-1].y, EP[i].x, EP[i].y);
else printf("%ds:(%d,%d)->(%d,%d)\n", ++cnt, 0, 0, EP[i].x, EP[i].y);
if(T[EP[i].x][EP[i].y])
for(int j = 1; j <= T[EP[i].x][EP[i].y]; j++) {
printf("%ds:FIGHT AT (%d,%d)\n", ++cnt, EP[i].x, EP[i].y);
}
}
}
void MEM() {
memcpy(EP, P, maxP*sizeof(node)); //反正是从(0, 0)点开始的 (0, 0)这个点就不用记录了
}
bool in_map(int x, int y) {
return (x < N && x >= 0 && y < M && y >= 0);
}
void dfs(int x, int y, int t, int cur) {
if(t > B_T[x][y]) return ;
else B_T[x][y] = t;
if(t > maxT) return ;
if(t + abs(x - N+1)+abs(y - M+1) >= maxT) return ;
if(x == N-1 && y == M-1) {
if(t < maxT) {
maxP = cur;
MEM();
maxT = t;
}
return ;
}
for(int i = 0; i < 4; i++) {
int tx = x + dirx[i];
int ty = y + diry[i];
if(in_map(tx, ty) && G[tx][ty] == '.') {
G[tx][ty] = 'X'; P[cur] = node(tx, ty);
dfs(tx, ty, t+T[tx][ty]+1, cur+1);
G[tx][ty] = '.'; P[cur] = node(-1, -1);
}
}
return ;
}
int main() {
while(~scanf("%d%d", &N, &M)) {
memset(T, 0, sizeof(T)); //只有这个每次需要重新初始化一下
getchar();
for(int i = 0; i < N; i++) {
for(int j = 0; j < M; j++) {
scanf("%c", &G[i][j]);
if(G[i][j] <= 57 && G[i][j] >= 49) {
T[i][j] = G[i][j] - 48;
G[i][j] = '.';
}
}
getchar();
}
G[0][0] = 'X';
maxT = INF;
for(int i = 0; i < N; i++)
for(int j = 0; j < M; j++)
B_T[i][j] = INF;
dfs(0, 0, 0, 0); //接下来选的第一个点开始
if(maxT != INF) Print();
else printf("God please help our poor hero.\n");
printf("FINISH\n");
}
return 0;
}
我辛辛苦苦的花了两个小时写了个BFS, 结果WA了, 因为他说的是要求最短的时间内找到公主, 我没有考虑这个,所以错了。
但是怎么说呢,我的BFS记录路径我以后就用这个格式了, 说实话dfs打印路径的时候我想了很久....WA代码(仅过了样例):
#include
#include
#include
#include
using namespace std;
const int maxn = 100+10;
int N, M, T[maxn][maxn], flag, tx, ty, tt, EX, EY, ET;
char G[maxn][maxn], ch;
int dirx[] = {0, 0, 1, -1};
int diry[] = {1, -1, 0, 0};
struct node{
int x, prex;
int y, prey;
int t;
node(){}
node(int _x, int _y, int _t, int _prex, int _prey) {
x = _x; y = _y; t = _t; prex = _prex; prey = _prey;
}
}P[maxn][maxn], temp;
void Print(int x, int y, int t) {
if(x == 0 && y == 0 ) return ;
Print(P[x][y].prex, P[x][y].prey, t-T[x][y]-1);
printf("%ds:(%d,%d)->(%d,%d)\n", t-T[x][y], P[x][y].prex, P[x][y].prey, x, y);
if(T[x][y]){
int tempt = t - T[x][y];
for(int i = 1; i <= T[x][y]; i++) {
printf("%ds:FIGHT AT (%d,%d)\n", tempt+i, x, y);
}
}
}
bool in_map(int x, int y) {
return (x >= 0 && x < N && y >= 0 && y < M);
}
int main() {
while(~scanf("%d%d", &N, &M)) {
getchar();
memset(T, 0, sizeof(T));
memset(P, 0, sizeof(P));
for(int i = 0; i < N; i++) {
for(int j = 0; j < M; j++) {
scanf("%c", &G[i][j]);
if(G[i][j] <= 57 && G[i][j] >= 49) {
T[i][j] = G[i][j] - 48;
G[i][j] = '.';
}
}
getchar();
}
P[0][0] = node{0, 0, 0, 0, 0};
queue Q;
G[0][0] = 'X';
Q.push(P[0][0]); flag = 0;
while(!Q.empty()) {
temp = Q.front(); Q.pop();
if(temp.x == N-1 && temp.y ==M-1){flag = 1; EX = temp.x; EY = temp.y; ET = temp.t; break;}
else
for(int i = 0; i < 4; i++) {
tx = temp.x + dirx[i];
ty = temp.y + diry[i];
if(in_map(tx, ty) && G[tx][ty] == '.') {
G[tx][ty] = 'X';
tt = temp.t + T[tx][ty] + 1;
P[tx][ty] = node(tx, ty, tt, temp.x, temp.y);
Q.push(P[tx][ty]);
}
}
}
if(flag) {
printf("It takes %d seconds to reach the target position, let me show you the way.\n", ET);
Print(EX, EY, ET);
}
else printf("God please help our poor hero.\n");
printf("FINISH\n");
}
return 0 ;
}
先看看A*算法:A*算法(选取最小估价值思想)
本宝宝终于AC了这一道题, 搜了一下题解报告, 他们都是用的BFS+优先队列,也就是上面的普通队列queue换成了priority_queue, 然后加了个cmp优先级判断结构体, 还有while中的Q.front换成了Q.top.就可以了。
思路:每一个点作为一个状态, 每一次有4种转移方式(4个方向),将四种选择都放入队列里面, 将每一个层次的状态中时间最少的先出队,然后其他的依次出队。每次先用用时最少的点进行扩展!!! 这是选取最小估价的思想(链接戳进)!
减时间的技巧:存图的时候可以省去初始化,直接存图, 遇到数字的特判好他的时间,然后将它设置为'.'就行。然后其他的细心点就行, 最难搞的部分感觉还是在dfs打印路径的时候, 想了很长时间。
我遇到的问题:一是没想到用优先队列; 二是用优先队列的时候,cmp结构体中的a.t >b.t 还是a.t < b.t 我还是弄不清楚, 感觉优先队列的优先级问题我还是没有弄懂。
下面是我的AC代码:
#include
#include
#include
#include
#include
using namespace std;
const int maxn = 100+10;
int N, M, T[maxn][maxn], flag, tx, ty, tt, EX, EY, ET;
char G[maxn][maxn], ch;
int dirx[] = {0, 0, 1, -1};
int diry[] = {1, -1, 0, 0};
struct node{
int x, prex;
int y, prey;
int t;
node(){}
node(int _x, int _y, int _t, int _prex, int _prey) {
x = _x; y = _y; t = _t; prex = _prex; prey = _prey;
}
}P[maxn][maxn], temp;
struct cmp{
bool operator() (const node& a, const node& b){
return a.t > b.t; //时间小的优先级高
}
};
void Print(int x, int y, int t) {
if(x == 0 && y == 0 ) return ;
Print(P[x][y].prex, P[x][y].prey, t-T[x][y]-1);
printf("%ds:(%d,%d)->(%d,%d)\n", t-T[x][y], P[x][y].prex, P[x][y].prey, x, y);
if(T[x][y]){
int tempt = t - T[x][y];
for(int i = 1; i <= T[x][y]; i++) {
printf("%ds:FIGHT AT (%d,%d)\n", tempt+i, x, y);
}
}
}
bool in_map(int x, int y) {
return (x >= 0 && x < N && y >= 0 && y < M);
}
int main() {
while(~scanf("%d%d", &N, &M)) {
getchar();
memset(T, 0, sizeof(T));
memset(P, 0, sizeof(P));
for(int i = 0; i < N; i++) {
for(int j = 0; j < M; j++) {
scanf("%c", &G[i][j]);
if(G[i][j] <= 57 && G[i][j] >= 49) {
T[i][j] = G[i][j] - 48;
G[i][j] = '.';
}
}
getchar();
}
P[0][0] = node{0, 0, 0, 0, 0};
priority_queue, cmp> Q;
G[0][0] = 'X';
Q.push(P[0][0]); flag = 0;
while(!Q.empty()) {
temp = Q.top(); Q.pop();
if(temp.x == N-1 && temp.y ==M-1){flag = 1; EX = temp.x; EY = temp.y; ET = temp.t; break;}
else
for(int i = 0; i < 4; i++) {
tx = temp.x + dirx[i];
ty = temp.y + diry[i];
if(in_map(tx, ty) && G[tx][ty] == '.') {
G[tx][ty] = 'X';
tt = temp.t + T[tx][ty] + 1;
P[tx][ty] = node(tx, ty, tt, temp.x, temp.y);
Q.push(P[tx][ty]);
}
}
}
if(flag) {
printf("It takes %d seconds to reach the target position, let me show you the way.\n", ET);
Print(EX, EY, ET);
}
else printf("God please help our poor hero.\n");
printf("FINISH\n");
}
return 0 ;
}