UVaOJ 10557 - XYZZY

——by A Code Rabbit


Description

玩一个游戏。

  • 一共有 n 个房间,每个房间都通向其他几个房间。
  • 你带着100点能量进入第一个房间,每进入一个房间,都会根据这个房间的属性增加或减少能量。
  • 一旦能量降为0或者低于0,你就 game over 。
  • 只有到达最后一个房间,你才能算胜利。

输入房间的数量和每个房间的情况,包括每个房间通往哪几个房间。

输出是否能取得胜利。

注意:

  • 房间的路是单向通行的,但是你可以不停地到达某个房间或绕圈子,使得你具有更多的能量。


Types

Date Structure :: Graphs


Analysis

注意这道题将会有回路。

通过回路,既可以使得你的能量无限大,但是你也可能在回路中出不来。

所以如果用搜索去做这道题,如何处理回路的情况是关键。

搜索的话有两种做法,DFS 和 BFS。


1. DFS

需要二重的 DFS,第一重就是常规地去走每一个能够走的房间。

而第二重,就是在第一重 DFS 时,碰到走过的房间,

如果此时能量大于上次来的时候的能量,就说明你可以利用这个回路来使自己的能量无穷大,此时,只要开启第二种 DFS ,看看你所在的房间,能否到达目的房间(路上无视计算能量的影响),即可。

如果此时能量小于或等于上次来的时候的能量,说明你没有必要走这个回路,退出搜索即可。


2. BFS

常规的 BFS ,不过在到底某个房间时,需要记录你到达这个房间的能量。

下次来到这个房间的时候,如果能量更低就不必将此时的状态入栈,如果能量更高就更新到达这个房间的能量值。

在搜索的时候,发现能量发生异常(能量值已经很大了,还没有退出队列),就说明这时候已经陷入环中无法自拔了,退出循环,判定游戏失败即可。


Solution

1. DFS

// UVaOJ 10557
// XYZZY
// by A Code Rabbit

#include <cstdio>
#include <cstring>

const int LIMITS = 120;

struct Room {
    int energy;
    int doorways[LIMITS];
    int num_doorways;
    int last_energy;
};

Room room[LIMITS];
int n;

bool is_visited[LIMITS];

bool CanArrive(int pos);
bool Search(int pos, int energy);

int main() {
    while (scanf("%d", &n), n != -1) {
        // Inputs and INIT status of rooms.
        for (int i = 1; i <= n; ++i) {
            scanf("%d%d", &room[i].energy, &room[i].num_doorways);
            for (int j = 0; j < room[i].num_doorways; ++j) {
                scanf("%d", &room[i].doorways[j]);
            }
            room[i].last_energy = -1;
            /* -1 means that the room is never visited. */
        }
        // Outputs.
        printf("%s\n", Search(1, 100) ? "winnable" : "hopeless");
    }

    return 0;
}

bool Search(int pos, int energy) {
    // Exit.
    if (energy <= 0) {
        return false;
    }
    // Judge whether this is target.
    if (pos == n) {
        return true;
    }
    // If enter this room secondly.
    if (room[pos].last_energy != -1) {
        if (energy > room[pos].last_energy) {
           /* ? */ memset(is_visited, false, sizeof(is_visited));
            if (CanArrive(pos)) {
                return true;
            }
        }
        return false;
    };
    // Continue.
    room[pos].last_energy = energy;
    for (int i = 0; i < room[pos].num_doorways; ++i) {
        int pos_room_new = room[pos].doorways[i];
        if (Search(pos_room_new, energy + room[pos_room_new].energy)) {
            return true;
        }
    }
    return false;
}


bool CanArrive(int pos) {
    // Exit.
    if (is_visited[pos]) {
        return false;
    }
    // Judge whether this is target.
    if (pos == n) {
        return true;
    }
    // Continue.
    is_visited[pos] = true;
    for (int i = 0; i < room[pos].num_doorways; ++i) {
        if (CanArrive(room[pos].doorways[i])) {
            return true;
        }
    }
    return false;
}


2. BFS
// UVaOJ 10557
// XYZZY
// by A Code Rabbit

#include <cstdio>
#include <cstring>

const int LIMITS_NUM_ROOM = 120;
const int LIMITS_QUEUE = 1000000;
const int LIMITS_ENERGY_NEED = 100000;

struct Room {
    int energy;
    int doorways[LIMITS_NUM_ROOM];
    int num_doorways;
    int last_energy;
};

Room room[LIMITS_NUM_ROOM];
int n;

struct Status {
    int pos;
    int energy;
};

Status queue[LIMITS_QUEUE];
int head, tail;
bool is_found;

void BFS();
void INIT();
void Search(int pos, int energy);

int main() {
    while (scanf("%d", &n), n != -1) {
        // Inputs and INIT status of rooms.
        for (int i = 1; i <= n; ++i) {
            scanf("%d%d", &room[i].energy, &room[i].num_doorways);
            for (int j = 0; j < room[i].num_doorways; ++j) {
                scanf("%d", &room[i].doorways[j]);
            }
            room[i].last_energy = 0;
        }
        // BFS.
        BFS();
        // Outputs.
        printf("%s\n", is_found ? "winnable" : "hopeless");
    }

    return 0;
}

void BFS() {
    INIT();
    Search(1, 100);
    while (head < tail) {
        // Judge whether searching fall into loops.
        if (queue[head].energy > LIMITS_ENERGY_NEED)
            break;
        int pos_room = queue[head].pos;
        for (int i = 0; i < room[pos_room].num_doorways; ++i) {
            int pos_room_new = room[pos_room].doorways[i];
            Search(pos_room_new, queue[head].energy + room[pos_room_new].energy);
        }
        ++head;
    }
}

void INIT() {
    head = 0;
    tail = 0;
    is_found = false;
}

void Search(int pos, int energy) {
    // Exit.
    if (is_found) {
        return;
    }
    if (energy <= 0) {
        return;
    }
    // Judge whether this is target.
    if (pos == n) {
        is_found = true;
        return;
    }
    // Update last energy of this room.
    if (energy > room[pos].last_energy) {
        room[pos].last_energy = energy;
    } else {
        return;
    }
    // Push.
    queue[tail].pos = pos;
    queue[tail].energy = energy;
    ++tail;
}



下载PDF

参考资料:无

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值