[UVA] 1229 - Sub-dictionary
In this problem, by the word ``dictionary" we mean a list of alphabetically ordered words and their associated explanations in the same language. A dictionary must contain the definition for any word that appears in the explanation of another word. So you see, if a dictionary defines N words, it has exactly N distinct words in it. Also, we know that in a dictionary no word appears in the definition of itself.
A sub-dictionary is a collection of dictionary's words and their definitions such that it can be published as an independent dictionary, obviously satisfying the mentioned condition. As a project of Computational Linguistics course, we are assigned to create a Lexical Knowledge Base which is the knowledge expressed by words. For this task we should create our knowledge foundation based on a dictionary.
It's really hard for the computer to study words automatically. So, we decided to manually teach it some common words. We start from an appropriate sub-dictionary. By understanding its words, a computer could extend its knowledge to the whole dictionary word by word. For instance, a word ``xyz" could be added to the computer's understanding if computer knows the meaning of every words used in xyz's definition. You are asked to write a program that can find the smallest extendable sub-dictionary for a specific dictionary.
Input
The input consists of multiple test cases. The first line of each test case is n (1n100) , the number of dictionary's words. Each of the next n lines contains a word and its definition (that has at most 30 words). Words are separated by blanks and are made up of small English letters less than 25 characters.
Output
For each test case, on the first line print the number of sub-dictionary's words and on the second line write the alphabetically sorted list of words (separated by blanks).
Sample Input
5 aue oizer piqoi oizer doy oizer hweqlo hweqlo hweqlo piqoi aue oizer piqoi piqoi aue aue 0
Sample Output
3 aue oizer piqoi
題目描述:
當機器人要理解所有單字時,內建字典最小為何?
題目解法:
理解題目會有點困難,一個字可以由好幾個單字解釋,因此當機器人字典內部存在這些字時,他便可以理解。
因此理解程度又會上升,最後可以理解所有字詞。
因此只要求一開始最小的字典大小。
作法就是最簡單的拓樸排序,一直拔點,直到最後剩下一團循環解釋的關係圖,那便是最小字典。
#include <stdio.h>
#include <vector>
#include <queue>
#include <algorithm>
#include <map>
#include <iostream>
#include <sstream>
using namespace std;
vector<int> g[105];
int main() {
int n, i, j, k;
string word, def, line;
while(scanf("%d", &n) == 1 && n) {
map<string, int> R;
for(i = 0; i < 105; i++)
g[i].clear();
cin.ignore(100, '\n');
int size = 0, indeg[105] = {};
while(n--) {
getline(cin, line);
stringstream sin(line);
sin >> word;
int &x = R[word];
if(x == 0) x = ++size;
while(sin >> def) {
int &y = R[def];
if(y == 0) y = ++size;
g[x].push_back(y);
indeg[y]++;
}
}
int ret = size, used[105] = {};
queue<int> Q;
for(i = 1; i <= size; i++)
if(indeg[i] == 0)
Q.push(i);
while(!Q.empty()) {
int tn = Q.front();
Q.pop();
ret--;
used[tn] = 1;
for(i = 0; i < g[tn].size(); i++) {
if(--indeg[g[tn][i]] == 0) {
Q.push(g[tn][i]);
}
}
}
printf("%d\n", ret);
string dictionary[105];
for(map<string, int>::iterator it = R.begin();
it != R.end(); it++) {
dictionary[it->second] = it->first;
}
string res[105];
for(i = 1, j = 0; i <= size; i++) {
if(used[i] == 0)
res[j++] = dictionary[i];
}
sort(res, res+ret);
for(i = 0; i < ret; i++) {
if(i) putchar(' ');
cout << res[i];
}
cout << endl;
}
return 0;
}