HDU4547 CD操作

          题意:告诉你CD操作的具体方法,然后给出当前目录和目标目录,问要多少步才能从当前目录到目标目录。

          解法:最近公共祖先模板题,但是要注意几种特殊情况,例如,当前目录是A,目标目录是B,而A是B的祖先,那么这样可以一步到达,另外,当只有一个节点的时候也会有询问,比如A A,那么这个时候是0,处理好这些,问题就解决了。。。

         #include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<queue>
#include<set>
#include<stack>
#include<vector>
#include<algorithm>
#include<iostream>
#include<map>
#include<math.h>
using namespace std;
//LCA灵魂是当搜索完一层的时候 才标记次节点为父亲
#define MAXN 100001 
map<string,int> mp;
int father[MAXN];
int n,m;
int in[MAXN];
bool flag[MAXN];
int root;
typedef struct Q
{
    int to,next;
}Q;
Q edge[MAXN*2];
int ans[MAXN];
int dp[MAXN];
int cnt,box[MAXN];
typedef struct F
{
    int from,to;
}F;
F sum[MAXN];
void Make_E(int from,int to)
{
      edge[++cnt].to=to;
      edge[cnt].next=box[from];
      box[from]=cnt;
}
typedef struct F1
{
    int to,next,index;
}F1;
F1 Edge[MAXN*2];
int cnt1,Box[MAXN];
void Make_E1(int from,int to,int C)
{
      Edge[++cnt1].to=to;
      Edge[cnt1].index=C;
      Edge[cnt1].next=Box[from];
      Box[from]=cnt1;
}
void Init()
{
      int i,j,k;
      char a[44],b[44];
      mp.clear();
      int count=0;
      cnt=0;
      cnt1=0;
      scanf("%d%d",&n,&m);
      for(i=1;i<=n;i++)
      {
         box[i]=-1;
         in[i]=0;
         Box[i]=-1;
     }
      for(i=1;i<n;i++)
      {
         father[i]=i;
         scanf("%s %s",a,b);
         int A,B;
         if(!mp[a])
         {
            mp[a]=++count;
         }
         if(!mp[b])
         {
            mp[b]=++count;
         }
         A=mp[a];
         B=mp[b];
         Make_E(B,A);
         in[A]++;
     }
     father[n]=n;
     for(i=1;i<=m;i++)
     {
           ans[i]=0;
           scanf("%s %s",a,b);
           int A=mp[a];
           int B=mp[b];
           sum[i].from=A;
           sum[i].to=B;
           Make_E1(A,B,i);
           Make_E1(B,A,i);
       }
       root=0;
       for(i=1;i<=n;i++)
       {
           if(in[i])
           continue;
           root=i;
       }
     return ;
}
//非路径压缩 
int find(int x)
{
     int r=x;
     while(r!=father[r])
     r=father[r];
      return r;
}
void bfs(int x)
{
      int i,j,k;
      flag[x]=1;
      for(i=Box[x];i+1;i=Edge[i].next)
     {
            int y=Edge[i].to;
            int index=Edge[i].index;
            if(flag[y])
            {
       if(x==y)
       {
  ans[index]=0;
  continue;
}
                int Y=find(y);
                if(sum[index].from==x&&sum[index].to==y)
                {
                    if(x==Y)
                    {
                        ans[index]=1;
                     }
                     else if(y==Y)
                     {
                        ans[index]=dp[x]-dp[Y];
                      }
                     else
                     {
                        ans[index]=1+dp[x]-dp[Y];
                     }
                }
                else
                {
                     if(y==Y)
                     {
                        ans[index]=1;
                     }
                     else if(Y==x)
                     {
                       ans[index]=dp[y]-dp[Y];
                      }
                     else
                     {
                        ans[index]=1+dp[y]-dp[Y];
                     }
                 }
            }
     }
      for(i=box[x];i+1;i=edge[i].next)
      {
         int to=edge[i].to;
         if(!flag[to])
         {
              dp[to]=dp[x]+1;
              bfs(to);
              father[to]=x;
         }
      }
     return ;
}
// LCA
void Slove()
{
      int i,j,k;
      dp[root]=0;
      memset(flag,0,sizeof(flag));
      bfs(root);
      for(i=1;i<=m;i++)
      printf("%d\n",ans[i]);
}
int main()
{
     int i,j,k;
     int t;
     scanf("%d",&t);
     while(t--)
     {
          Init();
          Slove();
      }
      return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值