水岸空间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(因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!

  • 6
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
SDUT-OJ(Software Development University of Tsinghua Online Judge)是一个在线编程平台,提供给清华大学软件学院的学生和爱好者练习和解决算法问题的环境,其中包括各种计算机科学题目,包括数据结构、算法、图形等。对于"最小生成树"(Minimum Spanning Tree, MST)问题,它是图论中的经典问题,目标是从一个加权无向图中找到一棵包含所有顶点的树,使得树的所有边的权重之和最小。 在C语言中,最常见的是使用Prim算法或Kruskal算法来求解最小生成树。Prim算法从一个顶点开始,逐步添加与当前生成树相连且权重最小的边,直到所有顶点都被包含;而Kruskal算法则是从小到大对所有边排序,每次选取没有形成环的新边加入到树中。 如果你想了解如何用C语言实现这些算法,这里简单概括一下: - 通常使用优先队列(堆)来存储边和它们的权重,以便快速查找最小值。 - 从任意一个顶点开始,遍历与其相邻的边,若新边不形成环,就更新树,并将新边加入优先队列。 - Kruskal算法: - 先将所有的边按照权重升序排序。 - 创建一个空的最小生成树,然后依次取出排序后的边,如果这条边连接的两个顶点不在同一个连通分量,则将其添加到树中。 如果你需要更详细的代码示例,或者有具体的问题想了解(比如如何处理环、如何实现优先队列等),请告诉我,我会为你提供相应的帮助。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值