机试指南第六章-搜索-例题自解

枚举:

枚举是最简单也是最直白的搜索方式,它依次尝试搜索空间中所有的解,测试其是否符合条件,若符合则输出答案,否则继续测试下一组解。

例6.1 百鸡问题

#include<iostream>
using namespace std;

int main()
{
    int n;
    while (cin >> n)
    {
        for (int x = 0; x <= 100; x++)
        {
            for (int y = 0; y <= 100 - x; y++)
            {
                int z = 100 - x - y;
                if (x * 5 * 3 + y * 3 * 3 + z <= n * 3)
                {
                    cout << "x=" << x << ",y=" << y << ",z=" << z << endl;
                }
            }
        }
    }
    return 0;
}

广度优先搜索(BFS:breadth-first search):

 例6.2 胜利大逃亡(广搜+剪枝)

AC代码:

#include<cstdio>
#include<queue>
using namespace std;

bool mark[50][50][50];//标记数组,用来确保每个结点只被访问一次
int maze[50][50][50];//保存立方体的信息
struct N //状态结构体
{
    int x, y, z; //结点坐标
    int t;//达到该结点的最短时间
};

queue<N> Q;//队列符合操作顺序,先读入起点,也先从起点开始遍历
int go[][3] = { 1,0,0,-1,0,0,0,1,0,0,-1,0,0,0,1,0,0,-1 };//六个方向

int BFS(int a, int b, int c)//广搜,返回最少耗时
{
    while (Q.empty() == false)//当队列中仍有元素可以拓展时,继续循环
    {
        N now = Q.front();//得到队头的状态
        Q.pop();//从队列中弹出队头的状态
        for (int i = 0; i < 6; i++)//依次拓展相应的六个结点
        {
            int nx = now.x + go[i][0];
            int ny = now.y + go[i][1];
            int nz = now.z + go[i][2];//计算新坐标
            if (nx < 0 || nx >= a || ny < 0 || ny >= b || nz < 0 || nz >= c)continue;//新坐标在立方体之外则丢弃该坐标
            if (maze[nx][ny][nz] == 1)continue;//该坐标为墙,丢弃
            if (mark[nx][ny][nz] == true)continue;//该坐标已被访问,丢弃
            N tmp;//新的状态
            tmp.x = nx;
            tmp.y = ny;
            tmp.z = nz;//新状态坐标
            tmp.t = now.t + 1;//新状态的耗时
            Q.push(tmp);//将新状态加入队列
            mark[nx][ny][nz] = true;
            if (nx == a - 1 && ny == b - 1 && nz == c - 1)return tmp.t;//该坐标为终点,直接返回其耗时
        }
    }
    return -1;//所有状态查找完之后仍然找不到所需坐标,返回-1
}

int main()
{
    int T;
    scanf("%d", &T);
    while (T--)
    {
        int a, b, c, t;
        scanf("%d%d%d%d", &a, &b, &c, &t);
        for (int i = 0; i < a; i++)
        {
            for (int j = 0; j < b; j++)
            {
                for (int k = 0; k < c; k++)
                {
                    scanf("%d", &maze[i][j][k]);
                    mark[i][j][k] = false;
                }
            }
        }
        while (Q.empty() == false) Q.pop();//清空上一个队列
        mark[0][0][0] = true;//标记起点
        N tmp;
        tmp.t = tmp.x = tmp.y = tmp.z = 0;
        Q.push(tmp);//将初始状态放入队列
        int ans = BFS(a, b, c);//广搜开始启动
        if (ans <= t)printf("%d\n", ans); //小于等于时间要求,输出
        else  printf("-1\n");
    }
    return 0;
}

TLE代码(使用cin超时了,数据量过大,scanf更快)

#include<iostream>
#include<queue>
using namespace std;

bool mark[50][50][50];//标记数组,用来确保每个结点只被访问一次
int maze[50][50][50];//保存立方体的信息
struct N //状态结构体
{
    int x, y, z; //结点坐标
    int t;//达到该结点的最短时间
};

queue<N> Q;//队列符合操作顺序,先读入起点,也先从起点开始遍历
int go[][3] = { 1,0,0,-1,0,0,0,1,0,0,-1,0,0,0,1,0,0,-1 };//六个方向

int BFS(int a, int b, int c)//广搜,返回最少耗时
{
    while (Q.empty() == false)//当队列中仍有元素可以拓展时,继续循环
    {
        N now = Q.front();//得到队头的状态
        Q.pop();//从队列中弹出队头的状态
        for (int i = 0; i < 6; i++)//依次拓展相应的六个结点
        {
            int nx = now.x + go[i][0];
            int ny = now.y + go[i][1];
            int nz = now.z + go[i][2];//计算新坐标
            if (nx < 0 || nx >= a || ny < 0 || ny >= b || nz < 0 || nz >= c)continue;//新坐标在立方体之外则丢弃该坐标
            if (maze[nx][ny][nz] == 1)continue;//该坐标为墙,丢弃
            if (mark[nx][ny][nz] == true)continue;//该坐标已被访问,丢弃
            N tmp;//新的状态
            tmp.x = nx;
            tmp.y = ny;
            tmp.z = nz;//新状态坐标
            tmp.t = now.t + 1;//新状态的耗时
            Q.push(tmp);//将新状态加入队列
            mark[nx][ny][nz] = true;
            if (nx == a - 1 && ny == b - 1 && nz == c - 1)return tmp.t;//该坐标为终点,直接返回其耗时
        }
    }
    return -1;//所有状态查找完之后仍然找不到所需坐标,返回-1
}

int main()
{
    int T;
    cin >> T;
    while (T--)
    {
        int a, b, c, t;
        cin >> a >> b >> c >> t;
        for (int i = 0; i < a; i++)
        {
            for (int j = 0; j < b; j++)
            {
                for (int k = 0; k < c; k++)
                {
                    cin >> maze[i][j][k];
                    mark[i][j][k] = false;
                }
            }
        }
        while (Q.empty() == false) Q.pop();//清空上一个队列
        mark[0][0][0] = true;//标记起点
        N tmp;
        tmp.t = tmp.x = tmp.y = tmp.z = 0;
        Q.push(tmp);//将初始状态放入队列
        int ans = BFS(a, b, c);//广搜开始启动
        if (ans <= t)cout << ans << endl;//小于等于时间要求,输出
        else cout << -1 << endl;
    }
    return 0;
}

原文地址:https://www.cnblogs.com/yun-an/p/11029331.html

时间: 2024-08-01 17:30:49

机试指南第六章-搜索-例题自解的相关文章

计算机考研机试指南(六) ——栈

机试指南 cha 3 栈的应用 括号匹配问题 1 #include <iostream> 2 #include <stdio.h> 3 #include <algorithm> 4 #include <queue> 5 #include <stack> 6 #include <math.h> 7 #include <string> 8 #include <string.h> 9 #include <std

【算法总结】二叉树(王道机试指南第三章)

我们从二叉树的遍历谈起. 众所周知,在对二叉树的遍历过程中,根据遍历每一个结点的左子树.结点本身.右子树的顺序不同可将对二叉树的遍历方法分为前序遍历.中序遍历.后序遍历.我们摒弃数据结构教科书上复杂的遍历方式,而是使用我们在上一章所重点讨论过的递归程序来简单的实现它. 假设二叉树结点由以下结构体表示: struct Node { Node *lchild;//指向其左儿子结点的指针,当其不存在左儿子时为NULL Node *rchild;//指向其右儿子结点的指针,当其不存在右儿子时为NULL

CCNA学习指南 第六章 下载

本章讲述静态路由和动态路由的配置.动态路由协议涉及RIPv1.RIPv2和IGRP,这三个动态路由协议都属于距离矢量型路由协议. CCNA学习指南 第六章 下载

机试指南第二章-经典入门-Hash的应用自解

Hash的应用: Hash即散列,不像数据结构与算法中讲的各种Hash方法和冲突处理等过多的阐述,以下主要介绍Hash在机试试题解答中的作用. 例2.5 统计同成绩学生人数 Hash解法AC代码:(一般想到的也是这种解法) #include<cstring> #include<iostream> using namespace std; int grade[105]; int main() { int n, m, index; memset(grade, 0, sizeof(gra

[华为机试真题]66.单词搜索

题目 代码 /*--------------------------------------- * 日期:2015-07-06 * 作者:SJF0115 * 题目:WordSearch * 来源:华为机试真题 -----------------------------------------*/ #include <iostream> #include <string> #include <vector> #include <stack> #include

机试指南第二章-经典入门-查找例题自解

查找: 对于查找问题,有难有易.可能只是直接地对某个数字的查找,也可能涉及搜索等相对难度更大的算法.这里先介绍查找的基础概念和方法. 例 2.9 找 x AC代码: #include<cstring> #include<iostream> using namespace std; int num[205]; int main() { int n, m, x; memset(num, 0, sizeof(num)); while (cin >> n) { bool fla

机试指南第二章-经典入门-贪心例题自解

例2.11 FatMouse's Trade 解题思路 贪心策略.每次都买剩余物品中性价比(即重量价格比)最高的物品,直到该物品被买完或者钱耗尽.若该物品已经被买完,则我们继续在剩余的物品中寻找性价比最高的物品 AC代码 #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; struct Thing { double j;

《N诺机试指南》(六)负二进制转化习题

先看题目: 意思:将一个十进制数进行负二进制转化,将一个十进制数进行二进制转化大家都很清楚,取余再除2向下取整,接着反序输出 负二进制转化类似:1.对-2取余,再取绝对值 2.存入结果数组里 3.将数减去余数再除-2 4.反顺序打印出来 代码: //负二进制转换 /* 道理与 十进制转二进制一样 注意:有多组输入 */ #include <stdio.h> #include <math.h> int main(){ int n; int result[105]; while(sca

javascript权威指南第六章,关于对象

之前一直对对象这东西搞不懂,最开始接触js,有些概念都不理解,买了两本书,有人推荐用高级程序设计做教材,还买了一本权威指南,花了几天时间,很快的把高级程序设计翻了一下,很多东西不知所云,第一遍也只想大概了解一下有哪些东西了,快速翻完后,决定开始看权威指南,从最基础的看起,先大概理解概念,也算两本书结合着看, 这次看呢,知道的东西比之前多了一些,虽然说,知识理解了,书上的例子能看懂,但自己还是写不出来,但是呢,继续加油,大学三年完了,感觉现在才真正想要好好学习,现在快一个月了,知道了一点皮毛,刚看