POJ 1300 Door Man

POJ 1300 DoorMan

一、题目描述

你是一座大庄园的管家。庄园有很多房间,编号为0123,…。你的主人是一个心不在焉的人,经常沿着走廊随意地把房间的门打开。多年来,你掌握了一个诀窍:沿着一个通道,穿过这些大房间,并把房门关上。你的问题是能否找到一条路径经过所有开着门的房间,并使得:

  • 1 通过门后立即把门关上
  • 2 关上了的门不再打开
  • 3 最后回到你自己的房间(房间0),并且所有的门都已经关闭了。

在本题中,给定房间列表,及连通房间的、开着的门,并给定一个起始房间,判断是否存在这样的一条路径。不需要输出这样的路径,只需判断是否存在。假定任意两个房间之间都是连通的(可能需要经过其他房间)。

输入描述
输入文件包含多个(最多可达100个)测试数据,每个测试数据之间没有空行隔开。
每个测试数据包括3 部分:
起始行- 格式为START M N,其中 M 为管理员起始所处的房间号,N 为房间的总数(1N20);
房间列表- 一共N 行,每行列出了一个房间通向其他房间的房间号(只需列出比它的号码大的房间号,可能有多个,按升序排列),比如房间3 有门通向房间157,则房间3 的信息行内容为5 7,第一行代表房间0,最后一行代表行间N1。有可能有些行为空行,当然最后一行肯定是空行,因为N1 是最大的房间号;两个房间之间可能有多扇门连通。终止行-内容为END
输入文件最后一行是ENDOFINPUT,表示输入结束。

输出描述
每个测试数据对应一行输出,如果能找到一条路关闭所有的门,并且回到房间0,则输出YES XX 是他关闭的门的总数,否则输出NO

二、前置知识

Q:如何处理带空格的字符串输入?

#include <iostream>
#include <sstream> //istringstream 必须包含这个头文件
#include <string>
using namespace std;
int main() {
    string source = "i an a boy";

    // 声明一个字符串输入流
    istringstream sin;
    // 将字符串导入到sin输入流中
    sin.str(source);

    // 分离的方法1
    string s;
    while (sin >> s) {
        cout << s << endl;
    }
    cout << "===============================" << endl;

    // 重复使用必须先清空
    sin.clear();
    // 重新加载,准备二次输入,或者sin的重用
    sin.str(source);
    string a, b, c, d;
    sin >> a >> b >> c >> d;
    cout << a << endl;
    cout << b << endl;
    cout << c << endl;
    cout << d << endl;
    return 0;
}

二、解题思路

以房间为顶点、连接房间之间的门为边构造图。根据题目的意思,输入文件中每个测试数据所构造的图都是连通的。本题实际上是判断一个图中是否存在欧拉回路或欧拉通路,要分两种情况考虑:

  • 1 如果所有的房间都有偶数个门(通往其他房间),那么有欧拉回路,可以从0 号房间出发,回到0 号房间。但是这种情况下,出发的房间必须为0,因为要求回到0 号房间。例如,第1 个测试数据所对应的图为图5.6(a),图中有浅色阴影的顶点(即顶点0),表示管家初始时所处的房间;在该测试数据中,管家可以回到0号房间。
  1. 有两个房间的门数为奇数,其余的都是偶数,如果出发的房间和0号房间的门数都是奇数,那么也可以从出发的房间到达0号房间,并且满足题目要求。但是不能从房间0出发,必须从另一个门数为奇数的房间出发。例如第23 个测试数据就是这种情形,对应的图为图(b)和图(c),输出的结果分别是NOYES 7。对于庄园的其他情形,都是不能完成题目中所要求的任务的,所以直接输出NO

本题的难点在于输入数据的处理:可以使用sscanf函数处理数据。

#include <cstdio>
#include <iostream>
#include <string>
#include <sstream>
#include <cstring>
using namespace std;

const int N = 20;
int m, n, d[N];

int main() {
#ifndef ONLINE_JUDGE
    freopen("POJ1300.in", "r", stdin);
#endif
    // 加快读入
    ios::sync_with_stdio(false), cin.tie(0);
    string s;
    while (getline(cin, s), s != "ENDOFINPUT") {
        memset(d, 0, sizeof d); // 多组测试数据,清空度数组

        istringstream sin;
        sin.str(s);         // 用s输入进行构建
        sin >> s >> m >> n; // 进1出3

        int cnt = 0;
        for (int i = 0; i < n; i++) {
            getline(cin, s);         // 读取整行
            if (!s.size()) continue; // 如果本行输入是空的,那么处理下一行
            sin.clear();             // istringstream这东西如果想重复使用,需要先清空
            sin.str(s);              // 用s输入进行构建
            int j;
            while (sin >> j) { // 循环输出j
                d[i]++, d[j]++;
                ++cnt;
            }
        }
        // 读入END
        getline(cin, s);

        // 检查欧拉回路和欧拉路径
        int odd = 0;
        for (int i = 0; i < n; i++)
            if (d[i] % 2) odd++;

        if (odd == 0 && m == 0)
            cout << "YES " << cnt << endl;
        else if (odd == 2 && m != 0)
            cout << "YES " << cnt << endl;
        else
            cout << "NO" << endl;
    }
    return 0;
}
posted @   糖豆爸爸  阅读(13)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!
历史上的今天:
2019-08-08 idea中自动deployment的步骤
2018-08-08 关于吃掉物理的二次聚合无法实现的需要之旁门左道实现法
Live2D
点击右上角即可分享
微信分享提示