HDU1026 Ignatius and the Princess I

时间:2021-04-03 08:18:33

问题链接HDU1026 Ignatius and the Princess I

题意简述:从矩阵的左上角走到右下角所需的最短时间,并且要求输出走的过程。矩阵中"."是可以走的,"X"是墙,n(数字1-9)是怪兽,需要战斗数字所示的时间。对于每个测试实例,先输入n和m,分别表示行数和列数,然后输入矩阵。

问题分析:显然求最短路径问题用BFS,另外由于有怪兽,所以搜索过程需要使用优先队列。一个典型的用分支限界法解决的问题。最小路径上每个点到出发点距离应该是最小的。

程序说明用节点矩阵grid[][]存储输入的矩阵,同时存储输入的矩阵和到起始点需要行走的最少步骤,以及最小路径上前一个节点坐标。这个程序运行时间上算是比较短的。

AC的C++语言程序如下:

/* HDU1026 Ignatius and the Princess I */

#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
#include <stack>

using namespace std;

#define DIRECTSIZE 4

struct direct {
    int drow;
    int dcol;
} direct[DIRECTSIZE] =
    {{0, -1}, {0, 1}, {-1, 0}, {1, 0}};

const int MAXN = 100;
const unsigned int MAXTIME = MAXN*MAXN*9+1;

struct gridnode {
    char v;
    int prevrow, prevcol;
    unsigned int mintime;
};

gridnode grid[MAXN+1][MAXN+1];

struct node {
    int row, col;
    unsigned int sumtime;

    bool operator<(const node n) const {
        return sumtime > n.sumtime;
    }
};

int n, m;
unsigned int mintime;
node start, end2, f, v;

int bfs()
{
    int ans = 0;

    grid[0][0].prevrow = -1;
    grid[0][0].prevcol = -1;
    grid[0][0].mintime = 0;

    start.row = 0;
    start.col = 0;
    start.sumtime = 0;

    end2.row = n - 1;
    end2.col = m - 1;

    mintime = MAXTIME;

    priority_queue<node> q;
    q.push(start);

    while(!q.empty()) {
        f = q.top();
        q.pop();

        if(f.row == end2.row && f.col == end2.col) {
            if(f.sumtime < mintime) {
                mintime = f.sumtime;
                ans = 1;
                continue;
            }
        }

        if(f.sumtime >= mintime)
            continue;

        for(int i=0; i<DIRECTSIZE; i++) {
            int nextrow = f.row + direct[i].drow;
            int nextcol = f.col + direct[i].dcol;

            if(0 <= nextrow && nextrow < n && 0 <= nextcol && nextcol < m) {
                if(grid[nextrow][nextcol].v == '.') {
                    // 曾经走过的点,这次时间长的话就不再走了
                    if(f.sumtime + 1 < grid[nextrow][nextcol].mintime) {
                        v.row = nextrow;
                        v.col = nextcol;
                        v.sumtime = f.sumtime + 1;
                        grid[v.row][v.col].mintime = v.sumtime;
                        grid[v.row][v.col].prevrow = f.row;
                        grid[v.row][v.col].prevcol = f.col;
                        q.push(v);
                    }
                } else if(grid[nextrow][nextcol].v != 'X') {
                    v.sumtime = f.sumtime + 1;
                    v.sumtime += grid[nextrow][nextcol].v - '0';
                    // 曾经走过的点,这次时间长的话就不再走了
                    if(v.sumtime < grid[nextrow][nextcol].mintime) {
                        v.row = nextrow;
                        v.col = nextcol;
                        grid[v.row][v.col].mintime = v.sumtime;
                        grid[v.row][v.col].prevrow = f.row;
                        grid[v.row][v.col].prevcol = f.col;
                        q.push(v);
                    }
                }
            }
        }
    }

    return ans;
}

void output_print()
{
    stack<node> s;
    node v1, v2;

    v.row = end2.row;
    v.col = end2.col;
    s.push(v);
    while(grid[v.row][v.col].prevrow != -1 || grid[v.row][v.col].prevcol != -1) {
        v2 = v;
        v.row = grid[v2.row][v2.col].prevrow;
        v.col = grid[v2.row][v2.col].prevcol;
        s.push(v);
    }


    printf("It takes %d seconds to reach the target position, let me show you the way.\n", mintime);

    int count = 0;
    v1 = s.top();
    s.pop();
    while(!s.empty()) {
        v2 = s.top();
        s.pop();
        printf("%ds:(%d,%d)->(%d,%d)\n", ++count, v1.row, v1.col, v2.row, v2.col);
        if(grid[v2.row][v2.col].v != '.') {
            for(int j=1; j<=grid[v2.row][v2.col].v-'0'; j++)
                printf("%ds:FIGHT AT (%d,%d)\n", ++count, v2.row, v2.col);
        }

        v1 = v2;
    }
}

char mygetchar()
{
    char c;

    while((c = getchar()) && (c == ' ' || c == '\t' || c == '\n'));

    return c;
}

int main()
{
    while(scanf("%d%d", &n, &m) != EOF) {
        for(int i=0; i<n; i++)
            for(int j=0; j<m; j++) {
                grid[i][j].v = mygetchar();
                grid[i][j].mintime = MAXTIME;
            }

        int ans = bfs();

        if(ans)
            output_print();
        else
            printf("God please help our poor hero.\n");
        printf("FINISH\n");
    }

    return 0;
}