Timus 1837. Isenbaev's Number

Timus 1837. Isenbaev's Number 要求计算 Isenbaev 数。


1837. Isenbaev's Number

Time Limit: 0.5 second
Memory Limit: 64 MB
Vladislav Isenbaev is a two-time champion of Ural, vice champion of TopCoder Open 2009, and absolute champion of ACM ICPC 2009. In the time you will spend reading this problem statement Vladislav would have solved a problem. Maybe, even two…
Since Vladislav Isenbaev graduated from the Specialized Educational and Scientific Center at Ural State University, many of the former and present contestants at USU have known him for quite a few years. Some of them are proud to say that they either played in the same team with him or played in the same team with one of his teammates…
Let us define  Isenbaev's number as follows. This number for Vladislav himself is 0. For people who played in the same team with him, the number is 1. For people who weren't his teammates but played in the same team with one or more of his teammates, the number is 2, and so on. Your task is to automate the process of calculating Isenbaev's numbers so that each contestant at USU would know their proximity to the ACM ICPC champion.

Input

The first line contains the number of teams  n (1 ≤  n ≤ 100). In each of the following  n lines you are given the names of the three members of the corresponding team. The names are separated with a space. Each name is a nonempty line consisting of English letters, and its length is at most 20 symbols. The first letter of a name is capital and the other letters are lowercase.

Output

For each contestant mentioned in the input data output a line with their name and Isenbaev's number. If the number is undefined, output “undefined” instead of it. The contestants must be ordered lexicographically.

Sample

input output
7
Isenbaev Oparin Toropov
Ayzenshteyn Oparin Samsonov
Ayzenshteyn Chevdar Samsonov
Fominykh Isenbaev Oparin
Dublennykh Fominykh Ivankov
Burmistrov Dublennykh Kurpilyanskiy
Cormen Leiserson Rivest
Ayzenshteyn 2
Burmistrov 3
Chevdar 3
Cormen undefined
Dublennykh 2
Fominykh 1
Isenbaev 0
Ivankov 2
Kurpilyanskiy 3
Leiserson undefined
Oparin 1
Rivest undefined
Samsonov 2
Toropov 1
Problem Author: folklore
Problem Source: Ural Championship 2011

Tags: graph theory


题意

这道题目是说俄罗斯乌拉尔大学有一个叫 Isenbaev 的牛人,他是 TopCoder Open 2009 和 ACM IPCP 2009 竞赛的双料冠军。许多人都以和他一同组队参赛为荣。退而其次,和他的队友一同参赛也是很有面子的。我们定义 Isenbaev 数如下:Isenbaev 他自己是 0,他的队友是 1。如果不是 Isenbaev 的队友,而是 Isenbaev 的队友参加的团队的成员,则是 2。以此类推。给出一些参赛队伍的名单,要求计算出这些队伍中每个人的 Isenbaev 数。

解答

下面就解答这道题目的是 C# 语言源程序:

using System;
using System.Collections.Generic;

// http://acm.timus.ru/problem.aspx?space=1&num=1837
static class Timus
{
  enum State { Initial, Prepare, Ready, Done };

  static readonly string VIP = "Isenbaev";
  static SortedDictionary<string, int> ranks;
  static string[][] teams;
  static State[] states;
  
  static void Main()
  {
    Initialize();
    Compute();
    foreach (var kvp in ranks) Console.WriteLine(kvp.Key + " "
      + ((kvp.Value < 0) ? "undefined" : kvp.Value.ToString()));
  }
  
  static void Initialize()
  {
    ranks = new SortedDictionary<string, int>();
    teams = new string[int.Parse(Console.ReadLine())][];
    states = new State[teams.Length]; // value is: Initial
    for (var i = 0; i < teams.Length; i++)
      foreach (var name in teams[i] = Console.ReadLine().Split())
      {
        ranks[name] = (name == VIP) ? 0 : -1;
        if (name == VIP) states[i] = State.Ready;
      }
  }
  
  static void Compute()
  {
    for (var rank = 1; ; rank++)
    {
      var done = true;
      for (var i = 0; i < states.Length; i++)
        if (states[i] == State.Ready)
        {
          foreach (var name in teams[i]) Compute(name, rank);
          states[i] = State.Done;
          done = false;
        }
      if (done) break;
      states.Replace(State.Prepare, State.Ready);
    }
  }
  
  static void Compute(string name, int rank)
  {
    if (ranks[name] >= 0) return;
    ranks[name] = rank;
    for (var i = 0; i < states.Length; i++)
      if (states[i] == State.Initial)
        foreach (var name2 in teams[i])
          if (name2 == name) states[i] = State.Prepare;
  }
  
  static void Replace<T>(this IList<T> c, T a, T b)
  {
    for (var i = 0; i < c.Count; i++)
      if (EqualityComparer<T>.Default.Equals(c[i], a)) c[i] = b;
  }
}

上述程序按照 Isenbave 数从小到大层次递进求解,分析如下:

  • line 10: 静态字段 ranks 表示各人的 Isenbave 数,其类型是 SortedDictionay,键就是人的姓名,值是 Isenbave 数。
  • line 11: 静态字段 teams 表示各参赛队伍,其类型是二维锯齿形数组。因为每个队伍的人数是不固定的。(题目中每个队伍均为三人,我们的程序不受这个限制)
  • line 12: 静态字段 states 表示求解过程中各参赛队伍的状态,计有“初始、预备、就绪、完毕”四种。请参见第 7 行的 State 枚举类型。
  • line 16 - 19: 首先调用 Initialize 方法读入数据并进行初始化,然后调用 Compute 方法求解,最后输出结果。
  • line 22 - 33: Initialize 方法。首先初始化上面提到的三个字段,注意 states 数组各元素的值被默认初始化为 State.Initial。然后循环读入各参赛队伍的数据,并且根据读入的人员是否为 Isenbave 进行相应处理。如果某个参赛队伍中有 Isenbave,该队伍的状态就设置为 State.Ready。
  • line 35 - 50: Compute 方法。从 1 开始递增 Isenbave 数进行求解,遍历各个参赛队伍,如果某个队伍的状态为 State.Ready 就遍历该队伍中的每个成员,调用下面要讲解的重载的 Compute 方法进行处理,处理后的队伍的状态改为 State.Done。最后,将处理后的状态为 State.Prepare 的队伍的都改为 State.Ready 状态,以便下次循环时继续求解。
  • line 52 - 60: 重载的 Compute 方法。如果队伍中某人的 Isenbave 数已经求出来了,就什么也不做立即返回。否则,设置他的 Isenbave 数。然后遍历状态为 State.Initial 的队伍,如果某人是该队伍的成员,则这个队伍的状态设置为 State.Prepare,以便在下个层次的循环中进行处理。
  • line 62 - 66: Replace 扩展方法。该方法用于对列表中的特定元素进行替换。可以作为一个小小的工具使用。

另一种解法

使用 List 代替数组的另外一种解法:

using System;
using System.Collections.Generic;

// http://acm.timus.ru/problem.aspx?space=1&num=1837
static class Timus
{
  static readonly string VIP = "Isenbaev";
  static SortedDictionary<string, int> ranks;
  static List<string[]> initial, prepare, ready;
  
  static void Main()
  {
    Initialize();
    Compute();
    foreach (var kvp in ranks) Console.WriteLine(kvp.Key + " "
      + ((kvp.Value < 0) ? "undefined" : kvp.Value.ToString()));
  }
  
  static void Initialize()
  {
    ranks = new SortedDictionary<string, int>();
    initial = new List<string[]>();
    ready = new List<string[]>();
    for (var i = int.Parse(Console.ReadLine()); i > 0; i--)
    {
      var team = Console.ReadLine().Split();
      var isReady = false;
      foreach (var name in team)
      {
        ranks[name] = (name == VIP) ? 0 : -1;
        if (name == VIP) isReady = true;
      }
      (isReady ? ready : initial).Add(team);
    }
  }
  
  static void Compute()
  {
    for (var rank = 1; ready.Count != 0; rank++, ready = prepare)
    {
      prepare = new List<string[]>();
      foreach (var team in ready)
        foreach (var name in team)
          Compute(name, rank);
    }
  }
  
  static void Compute(string name, int rank)
  {
    if (ranks[name] >= 0) return;
    ranks[name] = rank;
    for (var i = 0; i < initial.Count; i++)
      foreach (var name2 in initial[i])
      {
        if (name2 != name) continue;
        prepare.Add(initial[i]);
        initial.RemoveAt(i--);
        break;
      }
  }
}

在这个程序中,取消了二维锯齿数组 teams 和一维数组 states,使用三个 List 代替,即: initial、prepare 和 ready,分别对应原来的 Initial、Prepare 和 Ready  状态。而 Done 状态不再需要了,ready 中的队伍处理完毕后,直接将 prepare 改为 ready 进入下一层次的循环。这个程序在大数据量的情况下可能会比第一个程序快一点。

扩展阅读

维基百科中的“埃尔德什数(Erdős number)”应该是这道题目的背景。与此相关的还有“六度分隔理论(Small world experiment)”。


返回目录

你可能感兴趣的:(number)