1. 程式人生 > >LCA(離線演算法)

LCA(離線演算法)

CD操作

Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others)
Total Submission(s): 1010    Accepted Submission(s): 275


Problem Description   在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 方法一:

1700ms

#include"stdio.h"
#include"string.h"
#include"stdlib.h"
#define M 100009
#include"string"
#include"map"
#include"iostream"
using namespace std;
typedef struct st
{
    int u,v,next,w;
}E[M*3];
E edge,edge1;
int dis[M],head[M],head1[M],t,t1,use[M],in[M];
int f[M];
int finde(int x)
{
    if(x!=f[x])
        f[x]=finde(f[x]);
    return f[x];
}
void make(int u,int v)
{
    int x=finde(u);
    int y=finde(v);
    if(x!=y)
        f[x]=y;
}
void init()
{
    t=t1=0;
    memset(head,-1,sizeof(head));
    memset(head1,-1,sizeof(head1));
}
void add(int u,int v)
{
    edge[t].u=u;
    edge[t].v=v;
    edge[t].next=head[u];
    head[u]=t++;
}
void add1(int u,int v,int w)
{
    edge1[t1].u=u;
    edge1[t1].v=v;
    edge1[t1].w=w;
    edge1[t1].next=head1[u];
    head1[u]=t1++;
}
void dfs(int u)
{
    use[u]=1;
    int i;
    for(i=head[u];i!=-1;i=edge[i].next)
    {
        int v=edge[i].v;
        if(!use[v])
        {
            dis[v]=dis[u]+1;
            dfs(v);
            f[v]=u;
            make(u,v);
        }
    }
    for(i=head1[u];i!=-1;i=edge1[i].next)
    {
        int v=edge1[i].v;
        if(use[v])
        {
            edge1[i].w=edge1[i^1].w=f[finde(v)];
        }
    }
}
int main()
{
    int T,i,m,n,x,y;
    char ch1[60],ch2[60];
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&n,&m);
        map<string,int>mp;
        int k=1;
        init();
        memset(in,0,sizeof(in));
        for(i=1;i<n;i++)
        {
            scanf("%s%s",ch1,ch2);
            if(mp[ch1]==0)
            {
                x=k;
                mp[ch1]=k++;
            }
            else
                x=mp[ch1];
            if(mp[ch2]==0)
            {
                y=k;
                mp[ch2]=k++;
            }
            else
                y=mp[ch2];
            add(y,x);
            in[x]++;
        }
        while(m--)
        {
            scanf("%s%s",ch1,ch2);
            add1(mp[ch1],mp[ch2],0);
            add1(mp[ch2],mp[ch1],0);
        }
        memset(use,0,sizeof(use));
        memset(dis,0,sizeof(dis));
        for(i=1;i<=n;i++)
            f[i]=i;
        for(i=1;i<=n;i++)
        {
            if(!in[i])
                dfs(i);
        }
        for(i=0;i<t1;i+=2)
        {
            int u=edge1[i].u;
            int v=edge1[i].v;
            int mid=edge1[i].w;
            int p;
            if(v==mid)
                p=0;
            else
                p=1;
            printf("%d\n",dis[u]-dis[mid]+p);
        }
    }
}
方法二:

2700ms

#include"stdio.h"
#include"string.h"
#include"map"
#include"iostream"
#include"queue"
using namespace std;
#define M 100006
int dis[M];
int pre[M];
int rank[M],use[M],t,head[M];
int targan(int a,int b)
{
    if(a==b)
        return a;
    else if(rank[a]>rank[b])
        return targan(pre[a],b);
    else
        return targan(a,pre[b]);
}
struct st
{
    int u,v,next;
}edge[M*3];
void init()
{
    t=0;
    memset(head,-1,sizeof(head));

}
void add(int u,int v)
{
    edge[t].u=u;
    edge[t].v=v;
    edge[t].next=head[u];
    head[u]=t++;
}
void bfs(int s)
{
    queue<int>q;
    memset(use,0,sizeof(use));
    use[s]=1;
    memset(rank,0,sizeof(rank));
    q.push(s);
    while(!q.empty())
    {
        int u=q.front();
        q.pop();
        for(int i=head[u];i!=-1;i=edge[i].next)
        {
            int v=edge[i].v;
            if(!use[v])
            {
                use[v]=1;
                rank[v]=rank[u]+1;
                q.push(v);
            }
        }
    }
}
int main()
{
    int w;
    scanf("%d",&w);
    while(w--)
    {
        map<string,int>mp;
        int n,m,i;
        char ch1[444],ch2[444];
        init();
        scanf("%d%d",&n,&m);
        for(i=1;i<=n;i++)
            pre[i]=i;
        int t=1;
        for(i=1;i<n;i++)
        {
            scanf("%s%s",ch1,ch2);
            if(!mp[ch1])
                mp[ch1]=t++;
            if(!mp[ch2])
                mp[ch2]=t++;
            pre[mp[ch1]]=mp[ch2];
            dis[mp[ch1]]=1;
            add(mp[ch2],mp[ch1]);
        }
        int tep=-1;
        for(i=1;i<=n;i++)
            if(pre[i]==i)
            tep=i;
        bfs(tep);
        while(m--)
        {
            scanf("%s%s",ch1,ch2);
            int ans=targan(mp[ch1],mp[ch2]);
            if(ans!=mp[ch2])
                printf("%d\n",rank[mp[ch1]]-rank[ans]+1);
            else
                printf("%d\n",rank[mp[ch1]]-rank[ans]);
        }
    }
    return 0;

}



相關推薦

LCA離線演算法

CD操作 Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others) Total Submission(s): 1010    Accepted Submis

Algorithm---LCA倍增演算法

deep[i] 表示 i節點的深度, fa[i,j]表示 i 的 2^j (即2的j次方) 倍祖先,那麼fa[i , 0]即為節點i 的父親,然後就有一個遞推式子: fa[i,j]= fa [ fa [i,j-1] , j-1 ]  可以這樣理解: 設tmp = fa [

BZOJ-3626:LCA離線+樹鏈剖分

dep bzoj inpu 轉化 輸出 深度 定義 區間 三元組 Description 給出一個n個節點的有根樹(編號為0到n-1,根節點為0)。一個點的深度定義為這個節點到根的距離+1。設dep[i]表示點i的深度,LCA(i,j)表示i與j的最近公共祖先。有q次

HDU2586.How far away ?——近期公共祖先離線Tarjan

pos lin oid ces 離線 mar open const track http://acm.hdu.edu.cn/showproblem.php?pid=2586 給定一棵帶權有根樹,對於m個查詢(u,v),求得u到v之間的最短距離 那麽僅

小白python學習——機器學習篇——k-近鄰演算法KNN演算法

一、演算法理解 一般給你一資料集,作為該題目的資料(一個矩陣,每一行是所有特徵),而且每一組資料都是分了類,然後給你一個數據,讓這個你預測這組資料屬於什麼類別。你需要對資料集進行處理,如:歸一化數值。處理後可以用matplotlib繪製出影象,一般選兩個特徵繪製x,y軸,然後核心是計算出預測點到

B-DiningEK演算法

B - Dining   Cows are such finicky eaters. Each cow has a preference for certain foods and drinks, and she will consume no others. Farmer J

G - Oil Skimming ——二分圖匹配匈牙利演算法

G - Oil Skimming Thanks to a certain "green" resources company, there is a new profitable industry of oil skimming. There are large slicks of crude

Java多執行緒系列---“JUC原子類”01之 原子類的實現CAS演算法

轉自:https://blog.csdn.net/ls5718/article/details/52563959  & https://blog.csdn.net/mmoren/article/details/79185862(含部分修改)   在JDK 5之前Java語言是靠

資料結構與演算法JavaScript描述讀書筆記3檢索演算法

列表中查詢資料有兩種方法:順序查詢和二分查詢。順序查詢使用於元素隨機排列的列表;二分查詢適用於元素已排序的列表。二分查詢效率高,但是必須花費額外時間將列表中的元素排序 順序查詢 時間複雜度:O(n) function seqSearch(arr,data){ for(var i=

常用的memoryStoreEvictionPolicy快取演算法

EhCache常用的memoryStoreEvictionPolicy(快取演算法) 關於常用的快取演算法主要有三種: LRU:(Least Rencently Used)新來的物件替換掉使用時間算最近很少使用的物件。 LFU:(Least Frequently Used)替換掉

codevs 1022 覆蓋匈牙利演算法

codevs 1022 覆蓋(匈牙利演算法)   Time Limit: 1 Sec   Memory Limit: 128 MB Description    有一個N×M的單位方格中,其中有些方格是水塘,其他方格是陸地。如果要用1×2的矩陣區覆蓋(覆蓋過程不容許有任何部分重疊)這個陸

TensorFlow 實戰—— tf train優化演算法

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!        

Minimum Spanning Treeprim()演算法

滴答滴答---題目連結  For a given weighted graph $G = (V, E)$, find the minimum spanning tree (MST) of $G$ and print total weight of edges belong to the

Leetcode|Longest Palindromic Substring(最長迴文的幾種方法)Manacher演算法

Given a string S, find the longest palindromic substring in S. You may assume that the maximum length of S is 1000, and there ex

HDU2255:奔小康賺大錢KM演算法

奔小康賺大錢 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 14608   

大整數加法簡單演算法

大整數加法首先要了解加法的演算法,具體思路很簡單:     從低位到高位開始加,需要進位,正向陣列是高位在前,所以需要反向陣列開始加法。   程式碼如下,寫的麻煩了一點: #include<stdio.h> #include<i

轉:CDH5.7Hadoop叢集搭建離線

用了一週多的時間終於把CDH版Hadoop部署在了測試環境(部分元件未安裝成功),本文將就這個部署過程做個總結。 一、Hadoop版本選擇。 Hadoop大致可分為Apache Hadoop和第三方發行第三方發行版Hadoop,考慮到Hadoop叢集部署的高效,叢集的穩定性,以及後期集中的配

PAT——A1030 Travel Plandijkstra演算法

題目連結: #include<iostream> #include<set> #include<string> #include<cmath> #include<cstring> #include<algorithm> #i

HDU——3790 最短路徑問題dijkstra演算法

題目連結: #include<stdio.h> #include<string.h> #include<stdlib.h> #define maxn 1010 #define inf 0x3fffffff using namespace std; int co

最小生成樹圖文詳解Prim演算法

最小生成樹 就像幾個村莊都不相通, 要修路, 怎麼修, 這個花的錢最少, 這種最優選擇就是最小生成樹 設G = (V, E)是無向連通圖(V是結點集, E是邊集),相對於村莊例子,V就是那些村莊的集合,E就是村莊之間路的集合