#include <stdio.h>
#include <string.h>
#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <set>
using namespace std;
#define ERDOS "Erdos, P."
struct AuthorInfo
{
public:
AuthorInfo(const string& authorName) : m_Name(authorName), m_ErdosNo(-1)
{
}
void SetErdosNo(int x)
{
m_ErdosNo = x;
}
int GetErdosNo()
{
return m_ErdosNo;
}
void AddPaper(int x)
{
m_Papers.insert(x);
}
const string& GetName()
{
return m_Name;
}
bool InvolvedInPaper(int paper)
{
return (m_Papers.find(paper) != m_Papers.end());
}
const set<int>& GetPapers()
{
return m_Papers;
}
private:
string m_Name;
int m_ErdosNo;
set<int> m_Papers;
};
class AuthorErdosResult
{
public:
void AddResult(AuthorInfo* pAuthorInfo)
{
AddResult(pAuthorInfo->GetName(), pAuthorInfo->GetErdosNo());
}
int GetErdosNo(const string& authorName)
{
int nCnt = m_Result.count(authorName);
if (nCnt > 0)
return m_Result[authorName];
return -1;
}
private:
void AddResult(const string& authorName, int erdosNo)
{
m_Result.insert(pair<string, int>(authorName, erdosNo));
}
map<string, int> m_Result;
};
class UnhandledAuthorCol
{
typedef map<string, AuthorInfo*> AuthorsCol;
public:
~UnhandledAuthorCol()
{
AuthorsCol::iterator iter = m_authors.begin();
while(iter != m_authors.end())
{
delete iter->second;
++iter;
}
}
void AddAuthor(const string& authorName, int paper)
{
int cnt = m_authors.count(authorName);
if (cnt <= 0)
m_authors.insert(pair<string, AuthorInfo*>(authorName, new AuthorInfo(authorName)));
m_authors[authorName]->AddPaper(paper);
}
void ExtractAuthorsAndSetErdosNo(int erdosNo, int paper, vector<AuthorInfo*>& extractedAuthors)
{
AuthorsCol::iterator iter = m_authors.begin();
vector<string> toDeleteAuthors;
while(iter != m_authors.end())
{
if (iter->second->InvolvedInPaper(paper))
{
iter->second->SetErdosNo(erdosNo);
extractedAuthors.push_back(iter->second);
toDeleteAuthors.push_back((iter->first));
}
++iter;
}
for (int i = 0; i < toDeleteAuthors.size(); ++i)
m_authors.erase((toDeleteAuthors[i]));
}
AuthorInfo* ExtractAuthorsAndSetErdosNo(const string& name, int erdosNo)
{
AuthorsCol::iterator iter = m_authors.find(name);
if (iter == m_authors.end())
return NULL;
AuthorInfo* pResult = iter->second;
pResult->SetErdosNo(erdosNo);
m_authors.erase(iter);
return pResult;
}
private:
AuthorsCol m_authors;
};
class ErdosCalculator
{
public:
void AddInfo(char* line, int paper)
{
int begin = 0;
int end = 0;
while(true)
{
if (line[end] == '.')
{
char next = line[end + 1];
if (next == ':' || next == ',')
{
line[end + 1] = '\0';
m_UnhandledAuthors.AddAuthor(string(line + begin), paper);
if (next == ':')
{
return;
}
// else, then
// next should be ',', and the next of next should be ' '.
end += 3;
begin = end;
continue;
}
}
else if (line[end] == ':') // There can be no '.' before the ':'.
{
line[end] = '\0';
m_UnhandledAuthors.AddAuthor(string(line + begin), paper);
return;
}
++end;
}
}
void Calculate()
{
set<AuthorInfo*> handledAuthors;
AuthorInfo* pErdosSelf = m_UnhandledAuthors.ExtractAuthorsAndSetErdosNo(string(ERDOS), 0);
if (pErdosSelf == NULL)
{
pErdosSelf = new AuthorInfo(string(ERDOS));
pErdosSelf->SetErdosNo(0);
}
handledAuthors.insert(pErdosSelf);
vector<AuthorInfo*> addedAuthors;
int erdosNo = 1;
while(true)
{
set<AuthorInfo*>::iterator iter = handledAuthors.begin();
while(iter != handledAuthors.end())
{
const set<int>& papers = (*iter)->GetPapers();
set<int>::const_iterator const_iter = papers.begin();
while(const_iter != papers.end())
{
m_UnhandledAuthors.ExtractAuthorsAndSetErdosNo(erdosNo, *const_iter, addedAuthors);
++const_iter;
}
++iter;
}
ClearHandledAuthorInfos(handledAuthors);
int nCnt = addedAuthors.size();
if (nCnt <= 0)
break;
++erdosNo;
for (int i = 0; i < nCnt; ++i)
handledAuthors.insert(addedAuthors[i]);
addedAuthors.clear();
}
}
int GetErdosNo(char* pName)
{
return m_Result.GetErdosNo(string(pName));
}
private:
void ClearHandledAuthorInfos(set<AuthorInfo*>& authorInfos)
{
set<AuthorInfo*>::iterator iter = authorInfos.begin();
while(iter != authorInfos.end())
{
m_Result.AddResult(*iter);
delete (*iter);
++iter;
}
authorInfos.clear();
}
UnhandledAuthorCol m_UnhandledAuthors;
AuthorErdosResult m_Result;
};
#define MAX_CNT 4096
static void OutputAuthorErdosNo(char* name, int erdosNo)
{
if (erdosNo < 0)
cout << name << " infinity" << endl;
else
cout << name << " " << erdosNo << endl;
}
static void DoTestCase(int testCaseNo)
{
int nPaperCnt, nAuthorCnt;
cin >> nPaperCnt >> nAuthorCnt;
// cin.ignore();
char buf[MAX_CNT];
fgets(buf, MAX_CNT, stdin); // Consume the '\n' after the author's count.
ErdosCalculator calculator;
for (int i = 0; i < nPaperCnt; ++i)
{
fgets(buf, MAX_CNT, stdin);
calculator.AddInfo(buf, i);
}
calculator.Calculate();
cout << "Scenario " << testCaseNo << endl;
for (int i = 0; i < nAuthorCnt; ++i)
{
fgets(buf, MAX_CNT, stdin);
int len = strlen(buf);
if (buf[len - 1] == '\n')
buf[len - 1] = '\0'; // Throw away the last '\n'.
OutputAuthorErdosNo(buf, calculator.GetErdosNo(buf));
}
}
static void DoTest()
{
int nTestCaseCnt;
cin >> nTestCaseCnt;
for (int i = 1; i <= nTestCaseCnt; ++i)
{
DoTestCase(i);
}
}
int main(int argc, char* argv[])
{
DoTest();
return 0;
}