洛谷P2814 家谱

Posted Soda

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了洛谷P2814 家谱相关的知识,希望对你有一定的参考价值。

P2814 家谱

题目背景

现代的人对于本家族血统越来越感兴趣。

题目描述

给出充足的父子关系,请你编写程序找到某个人的最早的祖先。

输入输出格式

输入格式:

 

输入由多行组成,首先是一系列有关父子关系的描述,其中每一组父子关系中父亲只有一行,儿子可能有若干行,用#name的形式描写一组父子关系中的父亲的名字,用+name的形式描写一组父子关系中的儿子的名字;接下来用?name的形式表示要求该人的最早的祖先;最后用单独的一个$表示文件结束。

 

输出格式:

 

按照输入文件的要求顺序,求出每一个要找祖先的人的祖先,格式:本人的名字+一个空格+祖先的名字+回车。

 

输入输出样例

输入样例#1:
#George
+Rodney
#Arthur
+Gareth
+Walter
#Gareth
+Edward
?Edward
?Walter
?Rodney
?Arthur
$
输出样例#1:
Edward Arthur
Walter Arthur
Rodney George
Arthur Arthur

说明

规定每个人的名字都有且只有6个字符,而且首字母大写,且没有任意两个人的名字相同。最多可能有1000组父子关系,总人数最多可能达到50000人,家谱中的记载不超过30代。

技术分享
/*
    感觉这题应该是noipT1难度,hash成一个数然后当成一个点记录出度,因为一个人的父亲只可能有一个,所以直接模拟即可,但是最后两个点TLE
*/
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define mod 2333333
int cnt,map[2410000],du[2410000],to[5410000];
bool vis[2410000];
char s[50010][10],ch[10];
int ha(char c[]){
    int res=1;
    for(int i=1;i<=6;i++)
        res=(res*31%mod+(ch[i]-A+1)*19%mod)%mod;
    return res;
}
int main(){
    //freopen("Cola.txt","r",stdin);
    scanf("%s",ch);
    int now,cur;
    while(1){
        if(ch[0]==$)break;
        cur=ha(ch);
        if(!vis[cur]){
            cnt++;
            for(int i=0;i<6;i++)s[cnt][i]=ch[i+1];
            map[cur]=cnt;
            vis[cur]=1;
        }
        if(ch[0]==#){
            int fa=cur;
            while(1){
                scanf("%s",ch);
                if(ch[0]!=+)break;
                int now=ha(ch);
                if(!vis[now]){
                    cnt++;
                    for(int i=0;i<6;i++)s[cnt][i]=ch[i+1];
                    map[now]=cnt;
                    vis[now]=1;
                }
                to[now]=fa;
                du[now]++;
            }
        }
        if(ch[0]==?){
            now=ha(ch);
            //map[now]=cnt;
            cout<<s[map[now]]<< ;
            while(1){
                if(du[now]==0)break;
                now=to[now];
            }
            cout<<s[map[now]]<<endl;
            scanf("%s",ch);
        }
    }
}
80分 TLE
技术分享
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define mod 2333333
int cnt,map[2410000],zu[2410000];
bool vis[2410000];
char s[50010][10],ch[10];
int ha(char c[]){
    int res=1;
    for(int i=1;i<=6;i++)res=(res*27+ch[i]-A+1)%mod;
    return res;
}
int main(){
    scanf("%s",ch);
    int now,cur;
    for(int i=1;i<=50000;i++)zu[i]=i;
    while(1){
        if(ch[0]==$)break;
        cur=ha(ch);
        if(!vis[cur]){
            cnt++;
            for(int i=0;i<6;i++)s[cnt][i]=ch[i+1];
            map[cur]=cnt;
            vis[cur]=1;
        }
        if(ch[0]==#){
            int fa=cur;
            while(1){
                scanf("%s",ch);
                if(ch[0]!=+)break;
                int now=ha(ch);
                if(!vis[now]){
                    cnt++;
                    for(int i=0;i<6;i++)s[cnt][i]=ch[i+1];
                    map[now]=cnt;
                    vis[now]=1;
                }
                zu[map[now]]=zu[map[fa]];
            }
        }
        if(ch[0]==?){
            now=ha(ch);
            cout<<s[map[now]]<< ;
            cout<<s[zu[map[now]]]<<endl;
            scanf("%s",ch);
        }
    }
}
另附更改之后WA成50分的代码
技术分享
#include<bits/stdc++.h>
using namespace std;
map<string,string>father;
string fat(string x){//找爸爸
    if(x!=father[x])
        father[x]=fat(father[x]);
    return father[x];
}
int main(){
    char k;
    string f1,t;
    while(1){
        cin>>k;
        if(k==$) break;
        if(k==#){
            cin>>f1;
            if(father[f1]=="") father[f1]=f1;
            continue;
        }
        else if(k==+){
            cin>>t;
            father[t]=f1;
        }
        else if(k==?){
            cin>>t;
            cout<<t<< <<fat(t)<<endl;
        }
    }
    return 0;
}
100分 map+并查集

 

以上是关于洛谷P2814 家谱的主要内容,如果未能解决你的问题,请参考以下文章

家谱(gen)——洛谷P2814

洛谷P2814 家谱

洛谷 P2814 家谱

题解 P2814 家谱

P2814 家谱

P2814 家谱