Gitignore 2020 上海icpc区域赛
Gitignore 2020 上海icpc区域赛
题目大意:
给你n个可以删除的文件路径,m个不能删除的文件路径,问最后删去所有可以删除的文件路径的最短的次数是多少?
文件路径有五个限制:
- 文件路径不为空,且最后一定是一个文件,即不能以
/
结尾 - 目录不能以
/
开头 - 文件名和目录不为空,即不能有连续的
/
- 所有的文件路径一定互不相同
- 一个目录中不会出现子目录和最后的文件名相同
题解:
这个画个图其实就很明白了,最后一定会是一棵树,但是这棵树因为文件名和目录名可能相同,所以不能直接用名字来建树,我使用的是以字典树的方式来建树,这样可以消除文件名和目录名可能相同的影响,建好树之后,问题就变成,一棵树最少删去多少个节点,使得最后树上的节点都是我们需要的。
代码还是有点难码,因为要这里会有两个映射,一个是字符串到数字,一个是数字到树节点的映射。
要注意区分!
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 2e3+10;
typedef pair<int,int>pii;
map<pii,int>trie;
map<string,int>mp;
vector<int>G[maxn];
char s[maxn];
int now,tot,flag[maxn];
void init(){
now = tot = 0;
mp.clear(),trie.clear();
for(int i=0;i<=1005;i++) flag[i] = false,G[i].clear();
}
void insert(int len){
int u = 0;
string str = "";
for(int i=1;i<=len;i++){
if(s[i]=='/'){
if(!mp[str]) mp[str] = ++now;
int v = mp[str];
if(!trie[pii(u,v)]) trie[pii(u,v)] = ++tot,G[u].push_back(tot);
u = trie[pii(u,v)],str = "";
}
else str += s[i];
}
}
void update(int len){
int u = 0;
string str = "";
for(int i=1;i<=len;i++){
if(s[i]=='/'){
int v = mp[str];
if(!v||!trie[pii(u,v)]) return ;
u = trie[pii(u,v)];
str = "",flag[u] = true;
}
else str += s[i];
}
}
int dfs(int u){
int ans = 0;
if(!flag[u]) return 1;
for(int i=0;i<G[u].size();i++){
int v = G[u][i];
// printf("u = %d v = %d\n",u,v);
ans+=dfs(v);
}
return ans;
}
int main(){
int t;
scanf("%d",&t);
while(t--){
init();
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%s",s+1);
int len = strlen(s+1);
s[len+1] = '/',insert(len+1);
}
flag[0] = true;
for(int i=1;i<=m;i++){
scanf("%s",s+1);
int len = strlen(s+1);
s[len+1] = '/',update(len+1);
}
int ans = dfs(0);
printf("%d\n",ans);
}
return 0;
}