uva 10557 - XYZZY

点击打开链接


题目意思:给定n个编号为1-n的房间,每个房间有对应的能量值(-100 - 100),还有给定每一个房间的门的个数,以及通过这些门可以到哪些房间,有一个人从起始点(默认为0房间)开始走,问能否走到终点n房间,如果中间的能量为0或小于0则直接算不能到达。


解题思路:对于过去的搜索题,我么通常用一个vis[]数组标记是否走过,对于这题我么另vis[]数组存储的是从开始到这个点的能量值,还有我们用一个局部遍历energy表示从开始到当前点的能量的变化值(增加就是这个过程能量增大,反之),其它见一下代码,详解。


代码:



//直接dfs,我们知道对于有往回走的点 ,如果往回走的过程能量在增加,那么可知我们无限循环时可得到无穷的能量,所以这时候我们在用一个dfs去判断是否这一点可以达终点如果可以直接退出,不行返回进行下一步。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <queue>
#include <stack>
using namespace std;
const int MAXN = 110;

int vis[MAXN], mark[MAXN];//mark数组用来标记走过的路径(在判断是否可以到终点的dfs中用到)
int room[MAXN][MAXN]; //第一数是能量,第二个数是门的个数,第三个开始是能到的房间的编号
int n, flag;

//搜索是否能到最后点
void Dfs(int k) {
    if (mark[k])//如果走过该房间则退出
        return;
    if (k == n) {//到最后时候也退出
        flag = 1;//更新flag的值
        return;
    }
    if (mark[k] == 0) {//如果没走过
        mark[k] = 1;//标记上一点走过了
        for (int j = 0; j < room[k][1]; j++) {
            if (mark[room[k][j + 2]] == 0) {
                Dfs(room[k][j + 2]);//对每一个可能的情况Dfs
            }
        }
    }
}

//深搜求解能量
//这里我们就用一个局部变量energy表示从起始点到该位置的能量的变化值(有正有负),这样就可以对于每一个函数都有一个energy,所以这里要用局部变量,全局会出错
void dfs(int i , int energy) {
    vis[i] = 100 + energy;//求出当前点的能量总和
    if (vis[i] <= 0){//如果小于0,那么就直接退出
        return;
    }
    if (i == n) {//如果到终点就更新flag,退出
        flag = 1;
        return;
    }
    if (vis[i] > 0) {//大于0,继续向一步走
        for (int j = 0; j < room[i][1]; j++) {//遍历每一个可以到的房间
            if (vis[room[i][j + 2]] == -1) {//如果没被走过,直接往下走
                int k = room[i][j+2];
                dfs(room[i][j + 2] , energy + room[k][0]);//这里energy是加上room[k][0],说明到下一点的能量总的变化
            } 
            else {//如果走过,那么判断是否是能量增加
                int k = room[i][j+2];
                if  (room[k][0] + energy + 100 > vis[k]) {//判断重新走到这个点的值room[k][0] + energy + 100是否大于上一次的值vis[k]。
                    memset(mark, 0, sizeof (mark));//每次都要初始化为0
                    Dfs(i);//判断i这个点能否到终点(传K也一样)
                    if(flag)//如果可以到终点直接退出
                       return;
                }
            }
        }
    }
}

//处理问题函数
void solve() {
    memset(vis, -1, sizeof (vis));
    flag  = 0;//默认是为0
    vis[0] = 100;//起始点为100
    dfs(1 , 0);
    if (flag)
        printf("winnable\n");
    else
        printf("hopeless\n");
    
}

//主函数
int main() {
    while (scanf("%d", &n) && n != -1) {//输入注意一下
        for (int i = 1; i <= n; i++) {
            scanf("%d %d", &room[i][0], &room[i][1]);
            for (int k = 0; k < room[i][1]; k++)
                scanf("%d", &room[i][k + 2]);
        }
        solve();
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值