POJ 1470 Closest Common Ancestors - Tarjan

本文介绍了一个使用Tarjan算法解决最近公共祖先问题的程序实现,包括算法原理、代码解析及实例应用。

POJ 1470 Closest Common Ancestors

Wiki 上的 Tarjan 算法, Tarjan is an offline algorithm

http://en.wikipedia.org/wiki/Tarjan's_off-line_lowest_common_ancestors_algorithm

function TarjanOLCA(u)
     MakeSet(u);
     u.ancestor := u;
     for each v in u.children do
         TarjanOLCA(v);
         Union(u,v);
         Find(u).ancestor := u;
     u.colour := black;
     for each v such that {u,v} in P do
         if v.colour == black
             print "Tarjan's Lowest Common Ancestor of " + u +
                   " and " + v + " is " + Find(v).ancestor + "."

 然而我实现的与上面的稍微有些不同 

function TarjanOLCA(u, ancestor)
     MakeSet(u);
     u.ancestor := u;
     u.colour := black;
     for each v such that {u,v} in P do
         if v.colour == black
             print "Tarjan's Lowest Common Ancestor of " + u +
                   " and " + v + " is " + Find(v).ancestor + "."
     for each v in u.children do 
         TarjanOLCA(v, u); 
     Find(u).ancestor := u;

Code for this problem:

#include <iostream>
#include <cstring>
#include <string>
#include <cstdio>
#include <vector>
using namespace std;

//Closet common ancestors
//tarjan algorithm
const int N = 1000;
vector<int> edges[N], query[N];
int times[N];

int fa[N];
int find(int v) {
  return v == fa[v]? v : fa[v] = find(fa[v]);
}

void tarjan(int v, int f) {
  //cout<<"int tarjan:"<<v<<' '<<f<<endl;
  fa[v] = v;
  for (int i = 0; i < query[v].size(); ++i) {
    int u = query[v][i];
    if (fa[u] != -1) {
      //u, v's closet common ancestor is find(u)
      //cout<<u<<' '<<v<<" closet common ancestors is "<<find(u)<<endl;
      times[find(u)]++;
    }
  }
  for (int i = 0; i < edges[v].size(); ++i) {
    int u = edges[v][i];
    if (u == f) continue;
    tarjan(u, v);
  }
  fa[v] = f;
}

int main()
{
  int n, q, a, b, c;
  while (scanf("%d", &n) != EOF) {
    memset(fa, 0, sizeof(int) * (n + 1));
    for (int i = 1; i <= n; ++i) {
      edges[i].clear();
      query[i].clear();
    }
    //cout<<"start reading edge"<<endl;
    for (int i = 1; i <= n; ++i) {
      scanf("%d:(%d)", &a, &b);
      while (b--) {
        scanf("%d", &c);
        //cout<<a<<' '<<c<<endl;
        edges[a].push_back(c);
        fa[c]++;
      }
    }
    int r = -1;
    for (int i = 1; i <= n; ++i) {
      if (fa[i] == 0)
        r = i;
    }
    scanf("%d", &q);
    //cout<<"start reading query"<<endl;
    for (int i = 0; i < q; ++i) {
      scanf(" ( %d %d ) ", &a, &b);
      //cout<<a<<' '<<b<<endl;
      query[a].push_back(b);
      query[b].push_back(a);
    }
    memset(times, 0, sizeof(int) * (n + 1));
    memset(fa, -1, sizeof(int) * (n + 1));
    tarjan(r, r);
    for (int i = 1; i <= n; ++i) {
      if (times[i])
        printf("%d:%d\n", i, times[i]);
    }
  }
  return 0;
}





                
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值