先言
本题选自【水岸空间OJ】,欢迎各位加入!
题目简介
题目描述
现代的人对于本家族血统越来越感兴趣,现在给出充足的父子关系,请你编写程序找到某个人的最早的祖先。
输入说明
输入文件由多行组成,首先是一系列有关父子关系的描述,其中每一组父子关系由二行组成,用#name的形式描写一组父子关系中的父亲的名字,用+name的形式描写一组父子关系中的儿子的名字;接下来用?name的形式表示要求该人的最早的祖先;最后用单独的一个$表示文件结束。规定每个人的名字都有且只有6个字符,而且首字母大写,且没有任意两个人的名字相同。最多可能有1000组父子关系,总人数最多可能达到50000人,家谱中的记载不超过30代。
输出说明
按照输入文件的要求顺序,求出每一个要找祖先的人的祖先,格式:本人的名字+一个空格+祖先的名字+回车。
输入&输出样例
输入 | 输出 | |
样例1 | #George +Rodney #Arthur +Gareth +Walter #Gareth +Edward ?Edward ?Walter ?Rodney ?Arthur $ | Edward Arthur Walter Arthur Rodney George Arthur Arthur |
做题方法介绍
本题算法:图论(并查集)
其次,需要注意字符串读入的方法,如果你定义的是char[N][M](先需定义N和M),你可以使用以下方法读入
//前面的代码
i=1;
while(cin>>a[i]+1)
if(a[i][1]=='&') break;
//后面的代码
标准程序
C(因CSDN无法选择C语言,所以选择bash)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define maxn 50010
struct node{
char name[10];
}A[maxn];
int n;
int f[maxn];
int hash_val(char str[]){
int i;
for(i = 1;i <= n; i++){
if(strcmp(str,A[i].name)==0)return i;
}
return 0;
}
int find(int v){
if(f[v]==v)return v;
int F = find(f[v]);
f[v] = F;
return F;
}
int main()
{
n = 0;
char temp[10];
int last;
for(int i = 1;i <= 50001; i++){
f[i] = i;
}
while(scanf("%s",temp) && strcmp(temp,"$") != 0){
char str[10];
strcpy(str,&temp[1]);
int index = hash_val(str);
if(temp[0]=='#'){
if(!index){
strcpy(A[++n].name,str);
last = n;
}
else{
last = index;
}
}
if(temp[0]=='+'){
int now;
if(!index){
strcpy(A[++n].name,str);
now = n;
}
else{
now = index;
}
int fa = find(last);
int fb = find(now);
f[fb] = fa;
}
if(temp[0]=='?'){
int v = hash_val(str);
int fv = find(v);
printf("%s %s\n",str,A[fv].name);
}
}
return 0;
}
C++
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
#define NMAX 50002
struct tagPerson
{
char m_name[7];
int m_father;
} Person[NMAX];
int g_nPeople = 0;
void InitData();
int FindAncestor(const char szName[]);
int AddPerson(const char szName[]);
int CheckPerson(const char szName[]);
int main()
{
InitData();
return 0;
}
void InitData()
{
char szName[8] = "\0";
int nFather = 0;
char chFlag = '\0';
cin >>szName;
chFlag = szName[0];
while (chFlag != '$')
{
if (chFlag == '#')
{
nFather = FindAncestor(szName + 1);
cin >>szName;
chFlag = szName[0];
while (chFlag == '+')
{
int father = CheckPerson(szName + 1);
if (father == -1)
{
father = AddPerson(szName + 1);
}
Person[father].m_father = nFather;
cin >>szName;
chFlag = szName[0];
}
}
if (chFlag == '?')
{
nFather = FindAncestor(szName + 1);
cout <<szName+1 <<' ' <<Person[nFather].m_name <<endl;
cin >>szName;
chFlag = szName[0];
}
}
}
int FindAncestor(const char szName[])
{
int nFather = CheckPerson(szName);
if (nFather == -1)
{
nFather = AddPerson(szName);
}
else
{
while (Person[nFather].m_father != nFather)
{
nFather = Person[nFather].m_father;
}
}
return nFather;
}
int AddPerson(const char szName[])
{
Person[g_nPeople].m_father = g_nPeople;
strcpy(Person[g_nPeople].m_name, szName);
++g_nPeople;
return g_nPeople - 1;
}
int CheckPerson(const char szName[])
{
for (int i = 0; i < g_nPeople; ++i)
{
if (strcmp(szName, Person[i].m_name) == 0)
{
return i;
}
}
return -1;
}
Pascal(因CSDN无法选择Pascal语言,所以选择bash)
program jiapu;
var ch:char;
st,h:string;
w,re,ww:array[0..50002]of string;
f:array[0..50000]of longint;
i,j,k,now,xw,n,m,x,y,dd:longint;
procedure kp(l,r:longint);
var i,j,k:longint;mid,t:string;
begin
i:=l;j:=r;mid:=re[(i+j)div 2];
repeat
while re[i]<mid do inc(i);
while re[j]>mid do dec(j);
if i<=j then
begin
t:=re[i];re[i]:=re[j];re[j]:=t;
inc(i);dec(j);
end;
until i>j;
if i<r then kp(i,r);
if j>l then kp(l,j);
end;
function get(x:longint):longint;
begin
if f[x]=x then exit(x);
get:=get(f[x]);
f[x]:=get;
end;
function find(x:string):longint;
var l,r,mid:longint;
begin
mid:=dd;l:=1;r:=k;
while re[mid]<>x do
begin
if re[mid]>x then r:=mid-1;
if re[mid]<x then l:=mid+1;
mid:=(l+r)div 2;
end;
find:=mid;
end;
begin
readln(w[1]);
for i:=1 to 50000 do
f[i]:=i;
i:=1;
while w[i][1]<>'?' do
begin
ww[i]:=w[i];
delete(w[i],1,1);
inc(i);
readln(w[i]);
end;
h:=w[i];
dec(i);
for j:=1 to i-1 do
for k:=j+1 to i do
if w[j]=w[k] then w[j]:=' ';
k:=0;
for j:=1 to i do
if w[j]<>' 'then
begin
inc(k);
re[k]:=w[j];
end;
kp(1,k);
dd:=(1+k)div 2;
j:=1;
while j<=i do
begin
now:=j+1;
delete(ww[j],1,1);
m:=find(ww[j]);x:=get(m);
while ww[now][1]='+' do
begin
delete(ww[now],1,1);
n:=find(ww[now]);
f[n]:=x;
inc(now);
end;
j:=now;
end;
st:=h;
while st[1]<>'$'do
begin
delete(st,1,1);
x:=f[find(st)];
writeln(st,' ',re[x]);
readln(st);
end;
end.
最后
标准程序并非作者所写,但能保证正确,作者写的标准程序已经转交至水岸空间OJ!
如果本文章的各个部分有误,欢迎大家在评论区留言!同时邀请大家加入水岸空间OJ!