P1738洛谷的文件夹-树形结构-模拟

题目链接

题目描述

kkksc03是个非凡的空想家!在短时间内他设想了大量网页,然后总是交给可怜的lzn去实现。

洛谷的网页端,有很多文件夹,文件夹还套着文件夹。

例如:/luogu/application/controller表示根目录下有一个名称为luogu的文件夹,这个文件夹下有一个名称application的文件夹,其中还有名为controller的文件夹。

每个路径的第1个字符总是’/’,且没有两个连续的’/’,最后的字符不是’/’。所有名称仅包含数字和小写字母。

目前根目录是空的。kkksc03想好了很多应该有的文件夹路径名。问题是,需要是使这些文件夹都存在,需要新建几个文件夹呢?

输入输出格式

输入格式:

输入文件第1行为一个正整数N。

接下来N行,每行为一个描述路径的字符串,长度均不超过100。

输出格式:

输出应包含N行,每行1个正整数,第i行输出若要使第1个路径到第i个路径存在,最少需要新建多少个文件夹。

输入输出样例

输入样例#1: 复制
2
/luogu/application/controller
/luogu/application/view
输出样例#1: 复制
3
4

输入样例#2: 复制
3
/chicken
/chicken/egg
/chicken
输出样例#2: 复制
1
2
2

输入样例#3: 复制
4
/a
/a/b
/a/c
/b/b
输出样例#3: 复制
1
2
3
5

说明

数据规模:

对于所有数据,N<=1000。

对于20%数据,有N<=20;

对于50%数据,有N<=200;

对于30%数据,有对于所有路径最多存在两个’/’(包含第1个字符)。


这道题是洛谷上一道模拟题,关于文件夹的,我想应该是和字符串有关就拿来做了。

提供两种思路。一长一短


一、刚开始看这题,想可不可以用取巧的方法,每个文件夹的名字都不一样?然后划分文件夹就可以得出结果了。但马上发现这是不可能的。

再观察题目,因为是和文件夹有关,所以突然想到了树形结构,可以模拟树形结构来统计文件夹的数量。从根节点遍历,查找当前目录可不可以往下走,如果不可以,就新建一个目录,否则往下走。此思路的关键是构建这样一个结构体

struct Node {
    string name;
    vector<Node*> nexts;
};

然后模拟树形结构,思路简单,代码略长。

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

struct Node {
    string name;
    vector<Node*> nexts;
};
int n, cnt = 0;

void get_sts(string str, vector<string> &sts)
{
    str += '/';
    str.erase(str.begin());
    string tmp;
    for (size_t i = 0; i < str.size(); ++i) {
        if (str[i] == '/') {
            sts.push_back(tmp);
            tmp = "";
        } else tmp += str[i];
    }
}

void build(Node* root, vector<string> sts)
{
    Node* p = root;
    for (size_t i = 0; i < sts.size(); ++i) {
        bool flag = false;
        for (size_t j = 0; j < p->nexts.size(); ++j) {
            if (p->nexts[j]->name == sts[i]) {
                flag = true;
                p = p->nexts[j];
                break;
            }
        }
        if (flag == false) { // 新建目录
            while (i != sts.size()) {
                cnt++;
                Node* now = new Node;
                now->name = sts[i];
                p->nexts.push_back(now);
                ++i;
                p = p->nexts.back();
            }
        }
    }
}

void calc(Node *root)
{
    for (size_t i = 0; i < root->nexts.size(); ++i) {
        cout << root->nexts[i]->name << endl;
        calc(root->nexts[i]);
    }
}

int main()
{
    Node* root = new Node;
    root->name = "";
    cin >> n;
    for (int i = 1; i <= n; ++i) {
        string str;
        cin >> str;
        vector<string> sts;
        get_sts(str, sts);
        build(root, sts);
        cout << cnt << endl;
    }
}

二、题解中有位大佬的思路很好,让我大开眼界了(当然目前还是井底之蛙)。

他的思路乍一看就是我最早的取巧的方法,用set自动去重文件夹的名字,统计set元素数量即可。于是我怀着怀疑的态度去调试代码,发现他存的不是文件夹的名字,而是文件夹目录的名字!惊醒梦中人!故有此记

目录是唯一的,可以作为一个文件夹的唯一标识符。

#include <set>
#include <string>
#include <iostream>

int main() {
    int n;
    std::cin >> n;
    std::set<std::string> set;

    for (int i = 1; i <= n; ++i) {
        std::string s;
        std::cin >> s;
        std::string dir = "";
        for (size_t j = 1; j < s.size(); ++j) {
            if (s[j] == '/') {
                set.insert(dir);
                //std::cout << dir << std::endl;
            }
            dir += s[j];
        }
        set.insert(dir);

        std::cout << set.size() << std::endl;
    }
}
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值