三场网络赛终于告一段落了!唉,实力太弱了!跟北大、清华这些家伙差距太远了,比"我在你身边你却不知道我爱你"的距离还要远!
这道题没有来得及提交,自己下来写完的,把样例过了!留在博客上作个记念吧!记念我大学生涯失败的网络赛!
题目是这样的(英文原版):
- Description
- Kong belongs to a huge family. Recently he got a family name list which lists all men (no women) in his family over many generations. The list shows that the whole family has a common ancestor, let's call him Mr. X. Of course, everybody except Mr.X in the list is Mr. X's descendant. Everybody's father is shown in the list except that Mr. X's father is not recorded. We define that Mr.X's generation number is 0. His son's generation number is 1.His grandson's generation number is 2, and so on. In a word, everybody's generation number is 1 smaller than his son's generation number. Everybody's generation number is marked in some way in the list.
- Now Kong is willing to pay a lot of money for a program which can re-arrange the list as he requires ,and answer his questions such as how many brothers does a certain man have, etc. Please write this program for him.
- Input
- There are no more than 15 test cases.
- For each test case:
- The first line is an integer N( 1 <= N <= 30,000), indicating the number of names in the list.
- The second line is the name of Mr. X.
- In the next N-1 lines, there is a man's name in each line. And if the man's generation number is K, there are K dots( '.') before his name.
- Please note that :
- 1) A name consists of only letters or digits( '0'-'9').
- 2) All names are unique.
- 3) Every line's length is no more than 60 characters.
- 4) In the list, a man M's father is the closest one above M whose generation number is 1 less
- than M.
- 5) For any 2 adjacent lines in the list, if the above line's generation number is G1 and the lower
- line' s generation number is G2, than G2 <= G1 +1 is guaranteed.
- After the name list, a line containing an integer Q(1<=Q<=30,000) follows, meaning that there are
- Q queries or operations below.
- In the Next Q lines, each line indicates a query or operation. It can be in the following 3 formats:
- 1) L
- Print the family list in the same format as the input, but in a sorted way. The sorted way
- means that: if A and B are brothers(cousins don’t count), and A's name is alphabetically
- smaller than B's name, then A must appear earlier than B.
- 2) b name
- Print out how many brothers does "name" have, including "name" himself.
- 3) c name1 name2
- Print out the closest common ancestor of "name1" and "name2". "Closest" means the
- generation number is the largest. Since Mr. X has no ancestor in the list, so it's guaranteed
- that there is no question asking about Mr. X's ancestor.
- The input ends with N = 0.
- Output
- Already mentioned in the input.
- Sample input
- 9
- Kongs
- .son1
- ..son1son2
- ..son1son1
- ...sonkson2son1
- ...son1son2son2
- ..son1son3
- ...son1son3son1
- .son0
- 7
- L
- b son1son3son1
- b son1son2
- b sonkson2son1
- b son1
- c sonkson2son1 son1son2son2
- c son1son3son1 son1son2
- 0
这道题题意很简单,就是给你一个家谱关系树,然后问你几个问题:怎么将名字排序后输出?给你一个名字,查找他兄弟的个数;给你两个名字,查找他们最近公共祖先的名字。
刚开始,由于考虑到需要排序,我脑袋里冒出来的都是搜索树,set等可以自动排序的东西,东想西想,最后绚烂之极归于平淡,选择了结构体数组!这其实也是受线段树的启发,真的感觉最牛B的数据结构应该是数组!
好了,接下来困扰我好一会儿的问题就是:怎么实现结构体在set中的排序?
参考:http://cboard.cprogramming.com/cplusplus-programming/91781-stl-set-structs.html
一共有三种方式:
1、结构体内部重载:
bool operator<(const Node &a) const
{
return a.age < age;
}
2、结构体外部重载:
bool operator<(const Node& left,const Node& right)
{
return left.age < right.age;
}
3、定义比较结构体:
struct cmp_age{
inline bool operator()(const Node& left,const Node& right) const
{
return left.age < right.age;
}
};
我个人觉得第3种方法最灵活。
这里稍微提一下的是STL中的priority_queue自定义的排序与第三种非常相似。
priority_queue<Node, vector<Node> ,cmp_age> q;
参见代码实现:
- /*
- * set_struct_sort.cpp
- *
- * Created on: 2012-9-23
- * Author: Administrator
- */
- #include<iostream>
- #include<set>
- #include<string>
- #include<queue>
- #include<vector>
- using namespace std;
- struct Node{
- int age;
- string name;
- //method 1
- // bool operator<(const Node &a) const
- // {
- // return a.age < age;
- // }
- };
- //method 2
- bool operator<(const Node& left,const Node& right)
- {
- return left.age < right.age;
- }
- struct cmp_age{
- inline bool operator()(const Node& left,const Node& right) const
- {
- return left.age < right.age;
- }
- };
- struct cmp_name{
- inline bool operator()(const Node& left,const Node& right) const
- {
- return left.name.compare(right.name)<=0;
- }
- };
- set<Node,cmp_age> s1;
- set<Node,cmp_name> s2;
- set<Node> s3;
- priority_queue<Node ,vector<Node> ,cmp_age > q;
- void init_data_for_s_and_q(){
- Node n1,n2,n3,n4;
- n1.age=1; n1.name="jack";
- n2.age=6; n2.name="john";
- n3.age=5; n3.name="Tom";
- n4.age=12;n4.name="hank";
- s1.insert(n1);
- s1.insert(n2);
- s1.insert(n3);
- s1.insert(n4);
- s2.insert(s1.begin(),s1.end());
- s3.insert(s1.begin(),s1.end());
- q.push(n1);q.push(n2);q.push(n3);q.push(n4);
- }
- void print_data_for_s(){
- set<Node,cmp_name>::iterator it;
- cout<<"\ns1 sort by age:"<<endl;
- it=s1.begin();
- while(it!=s1.end()){
- cout<<it->age<<", "<<it->name<<endl;
- it++;
- }
- cout<<"\ns2 sort by name:"<<endl;
- it=s2.begin();
- while(it!=s2.end()){
- cout<<it->age<<", "<<it->name<<endl;
- it++;
- }
- cout<<"\ns3 sort by age:"<<endl;
- it=s3.begin();
- while(it!=s3.end()){
- cout<<it->age<<", "<<it->name<<endl;
- it++;
- }
- cout<<"\nprint priority_queue:"<<endl;
- Node n;
- while(!q.empty()){
- n=q.top();q.pop();
- cout<<n.age<<", "<<n.name<<endl;
- }
- }
- int main(){
- init_data_for_s_and_q();
- print_data_for_s();
- }
好了,把思路拉回来,这道题最恼火的地方其实在于把数据存储在数组中,这里需要用到栈。这里我都感觉有点儿写不清楚了!因为结构体是这样定义的:
struct Node{
string name;
int parent,id;
vector<int> sons;
};
一共四个元素:自己的名字,父亲在数组中的下标,自己输入时的id号(主要是排序后会用到),儿子结点在数组中的下标。
为了找到parent,这里需要借助刚才提到的栈father(用数组模拟)。
最后还有一点的是:怎么快速找到名字在数组中对应的下标呢?用用map来存储就可以了。
好了,解释这么多了,贴代码吧!
- //============================================================================
- /*
- * 2012 金华区网络赛 Problem J Family Name List
- * */
- //============================================================================
- #include <iostream>
- #include<string>
- #include<vector>
- #include<set>
- #include<map>
- using namespace std;
- #define M 30000
- struct Node{
- string name;
- int parent,id;
- vector<int> sons;
- };
- bool operator< (const Node & lhs, const Node & rhs){
- return lhs.name.compare( rhs.name)<=0;
- }
- map<string,int> ma;
- Node r[M];
- int father[M],idx;
- int level[M];
- //把家谱图排序后输出,这里用set解决
- void L(int cur){
- cout<<r[cur].name<<endl;
- int len=r[cur].sons.size();
- if(len!=0){
- set<Node> s;
- set<Node>::iterator it;
- for(int i=0;i<len;i++){
- s.insert(r[r[cur].sons.at(i)]);
- }
- it=s.begin();
- while(it!=s.end()){
- L(it->id);
- it++;
- }
- }
- }
- //计算兄弟的个数
- int calBrother(const string &name){
- map<string,int>::iterator it;
- it=ma.find(name);
- if(it!=ma.end()){
- int id=ma.find(name)->second;
- return r[r[id].parent].sons.size();
- }
- return -1;
- }
- //查找公共祖先
- void commonAnestor(const string &name1,const string &name2){
- if(name1.compare(name2)==0){
- cout<<name1<<endl;
- return;
- }
- int id1=ma.find(name1)->second,id2=ma.find(name2)->second;
- if(id1==-1||id2==-1){
- cout<<"error"<<endl;
- return;
- }
- string c1,c2;
- c1=r[r[id1].parent].name.substr(level[id1]-1);
- c2=r[r[id2].parent].name.substr(level[id2]-1);
- if(level[id1]==level[id2]){
- commonAnestor(c1,c2);
- }else if(level[id1]<level[id2]){
- commonAnestor(name1,c2);
- }else{
- commonAnestor(c1,name2);
- }
- }
- int main() {
- int n;
- while(1){
- cin>>n;
- if(n==0)break;
- string name;
- idx=-1;
- for(int i=0;i<n;i++){
- cin>>name;
- int j=0;
- while(name.at(j)=='.'){
- ++j;
- }
- level[i]=j;
- r[i].name=name;
- string cname=name.substr(j);
- ma.insert(pair<string,int>(cname,i));
- r[i].id=i;
- if(idx!=-1){
- if(j==level[father[idx]]){
- father[idx]=i;
- }else if(j>level[father[idx]]){
- father[++idx]=i;
- }else{//j<level[idx]
- idx-=(level[father[idx]]-j);
- father[idx]=i;
- }
- r[i].parent=father[idx-1];
- r[father[idx-1]].sons.push_back(i);
- }else{
- r[i].parent=-1;
- father[++idx]=i;
- }
- }
- int m;
- cin>>m;
- string name1,name2;
- for(int i=0;i<m;i++){
- cin>>name;
- if(name.compare("L")==0){
- L(0);
- }else if(name.compare("b")==0){
- cin>>name1;
- cout<<calBrother(name1)<<endl;
- }else{
- cin>>name1>>name2;
- commonAnestor(name1,name2);
- }
- }
- ma.clear();
- for(int i=0;i<n;i++){
- r[i].sons.clear();
- }
- }
- return 0;
- }