P9831 [ICPC2020 Shanghai R] Gitignore

P9831 [ICPC2020 Shanghai R] Gitignore - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

P9831 [ICPC2020 Shanghai R] Gitignore_第1张图片


只看题意翻译这道题是做不出来的,还要去看英文里面的规定(这里就不放英文了),主要问题是不要公用子文件夹。

例如:

1 / a / 2

2 / a / 3

文件夹a有2个,而非1个。

仔细阅读理解之后就会发现我们需要的结构是如下图所示的目录类型的树

P9831 [ICPC2020 Shanghai R] Gitignore_第2张图片

比较容易想到的就是给每个文件夹一个独一无二文件夹空间。

例如下图

P9831 [ICPC2020 Shanghai R] Gitignore_第3张图片

文件夹1的文件空间为1,文件空间里面还有一个文件夹1,由于此处内部的文件夹1没有内容,所以不需要给他赋值空间,如果有需要,可以加上空间。

大概能理解这个思想之后直接看代码。

AC代码

#include 
using namespace std;

int idx,T,ans;
mapf;//第一列文件初始化空间
bool a[10001];//空间是否可以被直接删除
bool vis[10001];
           //文件名 文件空间
vector>e[10001];//文件空间i 拥有的文件e[i]
//此处拥有的文件也有可能拥有文件,所以保留<文件名,文件空间>
string s,t;

void push_down(int x){
    if(vis[x])return;
    vis[x]=true;
    for(auto i:e[x])push_down(i.second);
}
void dfs(int x){
    if(vis[x])return;
    vis[x]=true;
    if(a[x]){//当前文件夹能删除,直接删除
        vis[x]=false;
        ans++;
        push_down(x);//标记此文件夹拥有的文件均不用再访问了.
        return;
    }
    for(auto i:e[x])dfs(i.second);//访问当前文件夹所有内容
}

void solve(){
    f.clear();
    ans=0;
    for(int i=1;i<=10000;++i){
        a[i]=vis[i]=false;
        e[i].clear();
    }
    
    int n,m;
    cin>>n>>m;
    for(int i=1;i<=n+m;++i){
        cin>>s,s+='/',t="";
        for(int j=0,k=0,now;j<(int)s.length();++j){
            if(s[j]=='/'){//找到"/" 说明一个文件名输入完毕
                if(k==0){//若k=0 说明是一级文件夹,最前面的均分配一个f[t]空间
                    if(!f[t])f[t]=++idx;//是第一次出现,分配空间idx,此处空间idx会一直递增,保证空间号不同
                    now=f[t];
                    k=1;
                }else{//不是一级文件夹,此处需要用到now来递归空间号
                    bool flag=true;
                    for(auto k:e[now]){//遍历前一次空间号now的内容
                        if(k.first==t){//如果文件t已经存在
                            flag=false;
                            now=k.second;//获取文件t的空间号,更新now,准备下一次使用
                        }
                    }
                    if(flag){//如果文件t不存在
                        e[now].push_back({t,++idx});//手动加入,并且赋予新的空间号
                        now=idx;//更新now,准备下一次使用
                    }
                }
                if(i<=n)a[now]=true;//前n个路径全都需要删除
                else a[now]=false;//后m个不需要删除
                t="";
            }else t+=s[j];
        }
    }
    for(auto i:f){//第一列开始读取文件夹
        if(a[i.second])ans++;//如果一级文件夹就需要删除,那就不需要再往下了
        else dfs(i.second);//深搜.
    }
    cout<>T;
    while(T--)solve();
    return 0;
}

你可能感兴趣的:(洛谷,算法,数据结构,c++)