水岸空间OJ-家谱

先言

本题选自【水岸空间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(因优快云无法选择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(因优快云无法选择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!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值