C - CD操作
C - CD操作
题目:
在Windows下我们可以通过cmd运行DOS的部分功能,其中CD是一条很有意思的命令,通过CD操作,我们可以改变当前目录。
这里我们简化一下问题,假设只有一个根目录,CD操作也只有两种方式:
1. CD 当前目录名\...\目标目录名 (中间可以包含若干目录,保证目标目录通过绝对路径可达)
2. CD .. (返回当前目录的上级目录)
现在给出当前目录和一个目标目录,请问最少需要几次CD操作才能将当前目录变成目标目录?
这里我们简化一下问题,假设只有一个根目录,CD操作也只有两种方式:
1. CD 当前目录名\...\目标目录名 (中间可以包含若干目录,保证目标目录通过绝对路径可达)
2. CD .. (返回当前目录的上级目录)
现在给出当前目录和一个目标目录,请问最少需要几次CD操作才能将当前目录变成目标目录?
Input
输入数据第一行包含一个整数T(T<=20),表示样例个数;
每个样例首先一行是两个整数N和M(1<=N,M<=100000),表示有N个目录和M个询问;
接下来N-1行每行两个目录名A B(目录名是只含有数字或字母,长度小于40的字符串),表示A的父目录是B。
最后M行每行两个目录名A B,表示询问将当前目录从A变成B最少要多少次CD操作。
数据保证合法,一定存在一个根目录,每个目录都能从根目录访问到。
Output
请输出每次询问的结果,每个查询的输出占一行。
Sample Input
2
3 1
B A
C A
B C
3 2
B A
C B
A C
C A
Sample Output
2
1
2
解题思路:
这道题用map的话会很方便,然后就是内存卡的比较紧
然后,有一个坑了我好久的地方,就是这道题存边只需要存一条边,而不是两条!!
其他的就是要找到根然后求LCA就行了
还有要注意的地方是,要注意到达的点是不是他们二者的LCA,如果是的话,就不需要加一
如果不是,那么计算出前一点到LCA点的深度差然后再加一
代码如下:
1 #include <bits/stdc++.h> 2 #define N 100050 3 using namespace std; 4 5 6 map<string,int> mp; 7 bool vis[N]; 8 int n,m,tot,tol; 9 int depth[N]; 10 int head[N]; 11 int father[N][25]; 12 struct node{ 13 int v; 14 int next; 15 }e[N]; 16 17 18 string s1,s2; 19 20 21 void add(int u,int v) 22 { 23 e[tol].v=v; 24 e[tol].next=head[u]; 25 head[u]=tol++; 26 } 27 28 29 void dfs(int now,int fa) 30 { 31 depth[now]=depth[fa]+1; 32 father[now][0]=fa; 33 for(int i=1; (1<<i)<=depth[now]; ++i) 34 father[now][i]=father[father[now][i-1]][i-1]; 35 for(int i=head[now]; i; i=e[i].next) 36 { 37 if(e[i].v!=fa) 38 dfs(e[i].v,now); 39 } 40 } 41 42 int lca(int u,int v) 43 { 44 if(depth[u]<depth[v]) 45 swap(u,v); 46 int d=depth[u]-depth[v]; 47 for(int i=0; i<=20; ++i) 48 if((1<<i)&d) 49 u=father[u][i]; 50 if(u==v) 51 return u; 52 for(int i=20; i>=0; --i) 53 { 54 if(depth[father[u][i]]<=0) 55 continue; 56 if(father[u][i]!=father[v][i]) 57 { 58 u=father[u][i]; 59 v=father[v][i]; 60 } 61 } 62 return father[u][0]; 63 } 64 65 int main() 66 { 67 int T; 68 scanf("%d",&T); 69 while(T--) 70 { 71 memset(father,0,sizeof(father)); 72 memset(head,-1,sizeof(head)); 73 memset(vis,0,sizeof(vis)); 74 memset(depth,0,sizeof(depth)); 75 mp.clear(); 76 tot=0; 77 tol=1; 78 cin>>n>>m; 79 for(int i=1;i<n;++i) 80 { 81 cin>>s1>>s2; 82 if(!mp[s1]) mp[s1]=++tot; 83 if(!mp[s2]) mp[s2]=++tot; 84 add(mp[s2],mp[s1]); 85 vis[mp[s1]]=true; 86 } 87 for(int i=1;i<=tot;++i) 88 { 89 if(!vis[i]) 90 { 91 dfs(i,0); 92 //cout<<"i="<<i<<endl; 93 break; 94 } 95 } 96 for(int i=0;i<m;++i) 97 { 98 cin>>s1>>s2; 99 int x=mp[s1],y=mp[s2]; 100 int c=lca(x,y); 101 //cout<<depth[x]<<" "<<depth[y]<<" "<<depth[c]<<endl; 102 //cout<<x<<" "<<y<<" "<<c<<endl; 103 int ans=depth[x]-depth[c]; 104 if(c!=y) 105 ans++; 106 cout<<ans<<endl; 107 } 108 } 109 return 0; 110 }