C - CD操作

C - CD操作

题目:
在Windows下我们可以通过cmd运行DOS的部分功能,其中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 }
posted @ 2020-01-03 10:54  小松QAQ  阅读(521)  评论(0编辑  收藏  举报