题2.pta数据结构题集-File Transfer (25分)


题2.pta数据结构题集-File Transfer (25分)


一、题目

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

二、题解

1.简析

并查集的常规题。由于这里电脑的编号是从1到N,所以不妨将一个数组下标当作电脑编号,对应的数组元素直接就是该编号电脑的父电脑编号,若该编号电脑为根电脑,则用一个负数表示它的父电脑,它的绝对值就是这棵树拥有的节点个数(用于按秩归并)。然后按并查集的find,union写就好。

2.代码

下面是第一次做敲的码,未用路径压缩

#include <stdio.h>
#include <stdlib.h>

#define Maxsize 100000

void finish_connect(int set[])//连接操作
{
    int c1,c2;
    int root1,root2;
    scanf("%d%d",&c1,&c2);
    root1=find_root(c1,set);//找寻c1,c2的根电脑
    root2=find_root(c2,set);
    if(root1==root2)//根电脑相同无需连接
    {
        return;
    }
    else
    {
        union_set(root1,root2,set);//通过连接c1,c2的根电脑连接c1,c2
    }
    return;
}

int check_connect(int set[])//检查两台电脑
{
    int c1,c2;
    int root1,root2;
    scanf("%d%d",&c1,&c2);
    root1=find_root(c1,set);
    root2=find_root(c2,set);
    if(root1==root2)//根电脑相同说明c1,c2连接
    {
        return 1;
    }
    else
    {
        return 0;
    }
}

void Check(int set[],int N)//检查所有电脑
{
    int i;
    int k=0;//用k记录根电脑的个数
    for(i=1;i<=N;i++)
    {
        if(set[i]<0)//set值为负数时方为根电脑
        {
            k++;
        }
    }
    if(k==1)//当只有一台根电脑时网络全部连通
    {
        printf("The network is connected.");
    }
    else
    {
        printf("There are %d components.",k);
    }
    return;
}

int find_root(int c,int set[])
{
    int root;
    for(;set[c]>=0;c=set[c]);
    root=c;
    return root;
}

void union_set(int root1,int root2,int set[])//按秩归并(大树接上小树)连接电脑
{
    //将set[root]设为单个集合元素个数的相反数,从而储存了树的规模
    if(set[root1]<set[root2])//root1为大树(注意:由于是负数比大小,所以越小规模越大)
    {
        set[root1]+=set[root2];//root1树接上root2树,元素个数增加为两树之和
        set[root2]=root1;//将root2树奉root1树为根
    }
    else
    {
        set[root2]+=set[root1];
        set[root1]=root2;
    }
    return;
}

int main()
{
    int N;
    int i;
    char key;
    int set[Maxsize];//由于电脑是按顺序编号所以直接利用数组下标表示电脑,进而用set[]表示该电脑的上头为哪个电脑
    int answer[Maxsize];//储存C的答案
    for(i=0;i<Maxsize;i++)
    {
        answer[i]=-1;
    }
    scanf("%d",&N);
    for(i=1;i<=N;i++)//用-1初始化所有电脑,表示都不连通
    {
        set[i]=-1;
    }
    i=0;
    do
    {
        key=getchar();
        switch(key)
        {
            case 'I':finish_connect(set);break;
            case 'C':answer[i]=check_connect(set);i++;break;
        }
    }while(key!='S');
    for(i=0;answer[i]!=-1;i++)
    {
        if(answer[i]==1)
        {
            printf("yes\n");
        }
        else
        {
            printf("no\n");
        }
    }
    Check(set,N);
    return 0;
}

第二次做敲的码,这个用路径压缩了

#include <bits/stdc++.h>

using namespace std;

int parent[10001];

void init()
{
    fill(parent,parent+10001,-1);
    return;
}

int find_root(int v)
{
    if(parent[v]<0)
    {
        return v;
    }
    else
    {
        return parent[v]=find_root(parent[v]);//路径压缩,会将路径上的节点的父节点都变成根节点,相当于直接将这些节点贴在了根节点上,大大缩短了下一次find的路径
    }
}

int check_set(int v1,int v2)
{
    int root1,root2;
    root1=find_root(v1);
    root2=find_root(v2);
    if(root1!=root2)
    {
        return 0;
    }
    else
    {
        return 1;
    }
}

void union_set(int v1,int v2)
{
    int root1,root2;
    root1=find_root(v1);
    root2=find_root(v2);
    if(root1==root2)
    {
        return;
    }
    if(parent[root1]<parent[root2])
    {
        parent[root1]+=parent[root2];
        parent[root2]=root1;
    }
    else
    {
        parent[root2]+=parent[root1];
        parent[root1]=root2;
    }
    return;
}

int count_set(int N)
{
    int num=0;
    for(int i=1;i<=N;i++)
    {
        if(parent[i]<0)
        {
            num++;
        }
    }
    return num;
}

int main()
{
    init();
    int N;
    cin>>N;
    char op;
    cin>>op;
    while(op!='S')
    {
        int v1,v2;
        cin>>v1>>v2;
        switch(op)
        {
            case 'C':
                if(check_set(v1,v2))
                {
                    printf("yes\n");
                }
                else
                {
                    printf("no\n");
                }
                break;
            case 'I':union_set(v1,v2);break;
        }
        cin>>op;
    }
    int num=count_set(N);
    if(num>1)
    {
        printf("There are %d components.\n",num);
    }
    else
    {
        printf("The network is connected.\n");
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值