OpenJudge 1804《小遊戲》題解報告

一、題目鏈接

屠龍寶刀點擊就送

二、思路

本題的路線可延伸到矩形板的外面,延伸多遠都沒關係。但是因爲題目要求的是最小的線段數量,則伸出一個格子跟伸出多個格子沒有區別。爲了簡單起見,伸出一個格子就好。這樣就可以把原來的矩形板的面積增加一圈,即列從[1, w]擴大爲[0, w+1],行從[1, h]擴大爲[0, h+1]。
本題可使用廣度優先搜索來解決。每個head格子出隊後,周圍最多有四個不同方向的相鄰格子可入隊。當某個方向的相鄰格子入隊後,優先往這個方向一直前進,在這個過程中不需要拐彎,經過的格子也不需要入隊,因爲入隊會導致拐彎次數增加。

三、代碼

#include <iostream>
#include <cstdio>
#include <queue>
#include <memory.h>
using namespace std;

struct grid
{
    int x;      //本題中x爲列
    int y;      //y爲行
    int step;   //第幾條線段,即變了幾次方向
};

int dx[]={0, 0, 0, -1, 1};//移動列
int dy[]={0, -1, 1, 0, 0};//移動行
int sx, sy, ex, ey, w, h;

const int maxN = 80;
char Map[maxN][maxN];
bool vis[maxN][maxN];

bool check(int x, int y)
{
    //因爲可跑到矩形板的外面,所以四個邊界都要加1
    if(x >= 0 && x <= w+1 && y >= 0 && y <= h+1 && !vis[x][y])
    {
        if(Map[x][y] == ' ' || (Map[x][y] == 'X' && x == ex && y == ey))
        {
            return true;
        }

        return false;
    }

    return false;
}

queue<grid>q;

void bfs()
{
    grid start;
    start.x = sx;
    start.y = sy;
    start.step = 0;

    vis[sx][sy] = true;
    q.push(start);

    while(!q.empty())
    {
        grid head = q.front();
        q.pop();
        grid Next; //相鄰的四個格子
        for(int i=1; i<=4; i++)
        {
            Next.x = head.x + dx[i];
            Next.y = head.y + dy[i];
            Next.step = head.step + 1; //每換個方向,線段數就會加1,所以step加1
            while(check(Next.x, Next.y))
            {
                if(Next.x == ex && Next.y == ey)
                {
                    printf("%d segments.\n", Next.step);
                    return;
                }

                vis[Next.x][Next.y] = true;
                q.push(Next);

                //往dx[i],dy[i]這個固定的方向一直前進,不會引起線段數量增加,所以step不加1
                //處於固定方向一直前進中途上的各個點,不需要進隊列,因爲進隊列就意味着可調方向,
                //調方向得到的線段數必然多於不調方向得到的線段樹。
                Next.x += dx[i];
                Next.y += dy[i];
            }
        }
    }

    printf("impossible.\n");

    return;
}

int main()
{
    //freopen("game.in", "r", stdin);

    int cnt=0;

    while(true)
    {
        cnt++;
        scanf("%d%d", &w, &h); //寬(列)和高(行)
        if(w==0 && h==0)
        {
            break;
        }

        memset(Map, ' ', sizeof(Map));

        getchar(); //吸收換行符

        for(int r = 1; r <= h; r++) //行
        {
            string str;
            getline(cin, str);
            for (int c = 1; c <= w; c++)//列
            {
                Map[c][r] = str[c - 1];
            }
        }

        printf("Board #%d:\n", cnt);
        int pairCnt = 0;

        while(true)
        {
            pairCnt++;
            scanf("%d%d%d%d", &sx, &sy, &ex, &ey);
            if(sx==0 && sy==0 && ex==0 && ey==0)
            {
                break;
            }

            printf("Pair %d: ", pairCnt);
            memset(vis, false, sizeof(vis));

            bfs();

            //注意queue沒有clear()函數,要清空得逐個彈出
            while(!q.empty())
            {
                q.pop();
            }
        }
        printf("\n");
    }

    return 0;
}
瞭解信息學奧賽請加微信307591841(QQ同號)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章