从纸质作者列表中计算鄂尔多斯数

时间:2013-10-03 22:23:24

标签: python python-2.7

Erdős数字描述了一个人与数学家PaulErdős之间的“协作距离”,以数学论文的作者身份衡量。要分配一个Erdős号码,某人必须是另一个具有有限Erdős号码的人的研究论文的共同作者。 PaulErdős的Erdős数为零。任何其他人的Erdős数字是k + 1,其中k是任何共同作者的最低Erdős数。 Wikipedia

鉴于作者(和论文)的列表,我想为一组作者制作一个Erdős编号。源数据如下(来自输入.txt文件):

1(means only one scenario from this input, could have more than one from other entries)

4 3
Smith, M.N., Martin, G., Erdos, P.: Newtonian forms of prime factors
Erdos, P., Reisig, W.: Stuttering in petri nets
Smith, M.N., Chen, X.: First order derivates in structured programming
Jablonski, T., Hsueh, Z.: Selfstabilizing data structures
Smith, M.N.
Hsueh, Z.
Chen, X.

计算Erdős数字的作者是:

Smith, M.N.
Hsueh, Z.
Chen, X.

我目前的计划是从每个条目中取出名称,并形成名称的列表(或列表列表)。但我不确定最好的方法。我该怎么用? numpy的?的ReadLine?

更新: 输出应如下所示:

Scenario 1
Smith, M.N. 1
Hsueh, Z. infinity
Chen, X. 2

3 个答案:

答案 0 :(得分:2)

为了更好地理解这个问题,请注意,这只是unweighted single-source shortest path problem,可以使用Breadth-first Search来解决。 您问题中的图表定义为:

  1. 每个节点代表作者。
  2. 两个节点之间有一条边,如果有一张纸,两个节点所代表的两位作者共同创作它。
  3. 对于您的示例,图表如下:

    Reisig
      |
      |
     Erdos -- Martin
      |      /
      |     /
      |    /
      |   /
      |  /
     Smith -- Chen
    
    
    Jablonski -- Hsueh
    

    因此算法最初会将距离0指定为Erdos,将无穷大指定给其他人。然后,当它迭代地访问邻居时,它指定增加的距离。因此,下一次迭代会将距离(或在本例中为鄂尔多斯数)1分配给Reisig,Martin和Smith。下一次和最后一次迭代将为Chen分配2的距离。 Jablonski和Hsueh的距离将保留为无限远。

    使用Adjacency List的图表表示:

    e = Erdos
    r = Reisig
    m = Martin
    s = Smith
    c = Chen
    j = Jablonski
    h = Hsueh
    
    e: r m s
    r: e
    m: e s
    s: e c
    c: s
    j: h
    h: j
    

    使用Python解决它的代码:

    import Queue
    
    def calc_erdos(adj_lst):
        erdos_numbers = {}
        queue = Queue.Queue()
        queue.put(('Erdos, P.', 0))
        while not queue.empty():
            (cur_author, dist) = queue.get()
            if cur_author not in erdos_numbers:
                erdos_numbers[cur_author] = dist
            for author in adj_lst[cur_author]:
                if author not in erdos_numbers:
                    queue.put((author, dist+1))
        return erdos_numbers
    
    def main():
        num_scenario = int(raw_input())
        raw_input() # Read blank line
        for idx_scenario in range(1, num_scenario+1):
            [num_papers, num_queries] = [int(num) for num in raw_input().split()]
            adj_lst = {}
            for _ in range(num_papers):
                paper = raw_input()
                [authors, title] = paper.split(':')
                authors = [author.strip() for author in authors.split(',')]
                authors = [', '.join(first_last) for first_last in zip(authors[::2], authors[1::2])]
                # Build the adjacency list
                for author in authors:
                    author_neighbors = adj_lst.get(author,set())
                    for coauthor in authors:
                        if coauthor == author:
                            continue
                        author_neighbors.add(coauthor)
                    adj_lst[author] = author_neighbors
    
            erdos_numbers = calc_erdos(adj_lst)
    
            print 'Scenario %d' % idx_scenario
            for _ in range(num_queries):
                author = raw_input()
                print '%s %s' % (author, erdos_numbers.get(author,'infinity'))
    
    if __name__=='__main__':
        main()
    

    与输入:

    1
    
    4 3
    Smith, M.N., Martin, G., Erdos, P.: Newtonian forms of prime factors
    Erdos, P., Reisig, W.: Stuttering in petri nets
    Smith, M.N., Chen, X.: First order derivates in structured programming
    Jablonski, T., Hsueh, Z.: Selfstabilizing data structures
    Smith, M.N.
    Hsueh, Z.
    Chen, X.
    

    将输出:

    Scenario 1
    Smith, M.N. 1
    Hsueh, Z. infinity
    Chen, X. 2
    

    注意

    更普遍的问题可以描述为single-source shortest path problem,最简单的解决方案是使用Djikstra's Algorithm

答案 1 :(得分:0)

我已经提交了一个问题的编辑,试图澄清你希望实现的目标。基于此,我编写了以下代码来回答您想要问的想法

f = ['Smith, M.N., Martin, G., Erdos, P.: Newtonian forms of prime factors',
'Erdos, P., Reisig, W.: Stuttering in petri nets',
'Smith, M.N., Chen, X.: First order derivates in structured programming',
'Jablonski, T., Hsueh, Z.: Selfstabilizing data structures']

author_en = {} # Dict to hold scores/author
coauthors = []
targets = ['Smith, M.N.','Hsueh, Z.','Chen, X.']

for line in f:
    # Split the line on the :
    authortext,papers = line.split(':')

    # Split on comma, then rejoin author (every 2)
    # See: http://stackoverflow.com/questions/9366650/string-splitting-after-every-other-comma-in-string-in-python
    authors = authortext.split(', ')
    authors = map(', '.join, zip(authors[::2], authors[1::2]))

    # Authors now contains a list of authors names    
    coauthors.append( authors )

    for author in authors:
        author_en[ author ] = None

author_en['Erdos, P.'] = 0 # Special case

此时我们现在有一个列表列表:每个列表包含来自给定出版物的共同作者和用于保存分数的词典。我们需要迭代每篇论文并为作者分配一个分数。我对鄂尔多斯得分的计算并不完全清楚,但你可能想要将得分分配循环直到没有变化 - 以便考虑以后影响早期得分的论文。

for ca in coauthors:
    minima = None
    for a in ca:
        if author_en[a] != None and ( author_en[a]<minima or minima is None ): # We have a score
            minima = author_en[a]

    if minima != None:
        for a in ca:
            if author_en[a] == None:
                author_en[a] = minima+1 # Lowest score of co-authors + 1

for author in targets:
    print "%s: %s" % ( author, author_en[author] )            

答案 2 :(得分:0)

万一有人在寻找Java实现:

import java.util.*;

public class P10044 {

public static void main(String[] args) {

    Scanner c = new Scanner(System.in);
    int cases = c.nextInt();

    for (int currentCase = 1; currentCase<=cases; currentCase++) {

        int p = c.nextInt();
        int n = c.nextInt();

        c.nextLine();

        HashMap<String, ArrayList<String>> graph = new HashMap<>();
        String[] testingNames = new String[n];
        ArrayList<String> authors = new ArrayList<>();

        HashMap<String, Integer> eNums = new HashMap<>();

        while (p-- > 0) {

            String[] paperAuthors = c.nextLine().split(":")[0].split("\\.,");
            for (int i = 0; i < paperAuthors.length; i++) {
                if (paperAuthors[i].charAt(paperAuthors[i].length() - 1) != '.')
                    paperAuthors[i] += '.';
                paperAuthors[i] = paperAuthors[i].trim();
            }

            for (String author : paperAuthors)
                if (!authors.contains(author))
                    authors.add(author);

            // create and update the graph
            for (String name : paperAuthors) {

                ArrayList<String> updatedValue;

                if (graph.keySet().contains(name))
                    updatedValue = graph.get(name);
                else
                    updatedValue = new ArrayList<>();

                for (String paperAuthor : paperAuthors)
                    if (!paperAuthor.equals(name))
                        updatedValue.add(paperAuthor);

                graph.put(name, updatedValue);

            }
        }


        //initialize the eNums map:
        for (String author : authors)
            if (!author.equals("Erdos, P."))
                eNums.put(author, Integer.MAX_VALUE);
            else
                eNums.put(author, 0);


        for (int i = 0; i < n; i++)
            testingNames[i] = c.nextLine();

        calculateEnums("Erdos, P.", graph, eNums);


        System.out.println("Scenario " + currentCase);
        for (String name : testingNames)
            if (!eNums.keySet().contains(name) || eNums.get(name) == Integer.MAX_VALUE)
                System.out.println(name + " infinity");
            else
                System.out.println(name + " " + eNums.get(name));

    }

}

private static void calculateEnums(String name, HashMap<String, ArrayList<String>> graph,
                                   HashMap<String, Integer> eNums) {

    ArrayList<String> notCalculated = new ArrayList<>();
    notCalculated.add(name);

    while (notCalculated.size() > 0) {
        String currentName = notCalculated.get(0);
        for (String connectedName : graph.get(currentName)) {
            if (eNums.get(connectedName) > eNums.get(currentName)) {
                eNums.put(connectedName, eNums.get(currentName) + 1);
                if(!notCalculated.contains(connectedName))
                    notCalculated.add(connectedName);
            }
        }
        notCalculated.remove(0);
    }

//        recursive implementation but will result in TLE

//        for(String connected: graph.get(name)) {
//            if (eNums.get(connected) > eNums.get(name)) {
//                eNums.put(connected, eNums.get(name) + 1);
//                calculateEnums(connected, graph, eNums);
//            }
//        }
}
}