zoukankan      html  css  js  c++  java
  • 【3.16高一(第二学期)模拟测试】 T3,T4题解

      看到这个标题我想你一定会想为什么小编只发T3,T4的题解,原因有很多:1)小编也不怎么会讲;2)小编搜遍各大OJ,都没有找到可以提交的地方;3)虽然给了测试数据,小编懒得一个一个试。如果你找到了测评网址,欢迎留言。

    先说T3,题目如下:

    C、团伙 
    【问题描述】
        TEIAI 集团共有 n 名员工,编号为 1~n。由于长期的权力斗争,他们形成了
    复杂的势力网络。对于任意两名员工,他们可能是朋友,可能是敌人,也可能没
    什么关系。并且这种关系满足:(1)朋友的朋友是我的朋友;(2)敌人的敌
    人也是我的朋友。为了抱团取暖,党同伐异,员工们形成了若干团伙,每个团伙
    均满足:团伙内的所有人互为朋友,团伙外的每个人都不是朋友。
     集团的高层认为,这种斗争关系可以加速优胜劣汰的过程,从而促进集团的
    盈利。他们通过暗访得到了这样的 m 条信息:每条信息包含 3 个值 p,x,y,
    p=F 表示员工 x 与 y 是朋友,p=E 表示员工 x 与 y 是敌人。请你根据这 m 条信
    息,判断这些员工最多可能形成多少个团伙?
    【输入格式】
      第 1 行为 n 和 m,1<n<1000,1<=m<=5000;
      以下 m 行,每行为 pxy。
    【输出格式】
      一个整数,表示这 n 个人最多可能有几个团伙。
    【输入样例】 
      64
      E14
      F35
      F46
      E12
    【输出样例】 
    3
    【样例说明】{1},{2,4,6},{3,5}

      看起来这道题需要好好思索一番,此题一看就知道必须要用并查集(不会点这里)。首先,题目中出现了两种关系,分别是朋友关系和敌人关系,那么就要分类讨论了,先看朋友关系,这个好说,直接合并就可以了;那么敌人关系呢?根据敌人的敌人是朋友这个条件,只需要分别把敌人和另一个敌人的敌人合并即可。

    代码如下:

     1 #include<iostream>
     2 using namespace std;
     3 int n,m,p,q,a[10000],ans=0,num[10000];char c,ch;
     4 int find(int x)//并查集
     5 {
     6     if(x==a[x]) return x;
     7     else return a[x]=find(a[x]);
     8 }
     9 int main()
    10 {
    11     //freopen("group.in","r",stdin);
    12     //freopen("group.out","w",stdout);
    13     cin>>n>>m;
    14     for(int i=1;i<=n*2;i++) a[i]=i;//为了后续操作更方便,将1~n存为每一个人的祖先,n+1~n+n为1~n每个人的敌人,例如1和1+n是敌人关系
    15     for(int i=1;i<=m;i++)
    16     {
    17         cin>>c;
    18         cin>>p>>q;
    19         if(c=='F') a[find(p)]=find(q);//朋友关系直接合并
    20         else
    21         {
    22              a[find(p+n)]=find(q);//将敌人与敌人的敌人合并
    23             a[find(q+n)]=find(p);//同上
    24         }
    25     }
    26     for(int i=1;i<=n;i++)
    27     if(a[i]==i) ans++;//判断有多少个祖先即可知道有多少个团伙
    28     cout<<ans;
    29     return 0;
    30 }

    T4,题目如下:

    D、家谱 
    【问题描述】 
    给定一系列父子关系,求某些人的祖先。“祖先”指的是从该人开始,沿父
    子关系向上追溯可以达到的辈分最大的人。
    【输入格式】 
    每行包含一个人名和一个标识符。标识符紧贴在名字的前面,不同标识符的
    含义如下:(人名用 Name 指代)
    #Name:从下一行开始,每一个以标识符+开头的人名都是 Name 的儿子,
    直至遇到第一个不以+开头的人名;
    +Name:上一个用#标识的人的儿子;
    ?Name:要求输出 Name 的祖先。
    最后一行用一个字符$表示输入结束。
    【输出格式】
    按照输入文件的要求顺序,求出每一个用?标识的人的祖先,格式:本人的
    名字+一个空格+祖先的名字+回车。
    【输入样例】 
        #George
        +Rodney
        #Arthur
        +Gareth
        +Walter
        #Gareth
        +Edward
        ?Edward
        ?Walter
        ?Rodney
        ?Arthur
        $
    【输出样例】 
        EdwardArthur
        WalterArthur
        RodneyGeorge
        ArthurArthur
    【数据规模】 
     输入文件的总行数≤200,000。

      这道题与之前T3一样,需要用到并查集,但是合并是一件很麻烦的事情,如果装换成序号来做就太麻烦了,还会出现各种不必要的麻烦。那么就要请出传奇的map了。

      map是什么呢?用东西总得加头文件吧,要加上#include<map>才能用,map主要用来使两个元素发生联系,并且这两个元素可以是任意类型,这样数组下标就可以用string了。

    代码如下:

     1 #include<iostream>
     2 #include<cstring>
     3 #include<map>
     4 using namespace std;
     5 map<string,string>a;//尖括号内的两种类型可以分别当成数组下标与数组值的类型 
     6 string c,s;char ch;
     7 string find(string x)//字符串+并查集 
     8 {
     9     if(a[x]==x) return x;
    10     else return a[x]=find(a[x]);
    11 }
    12 int main()
    13 {
    14     for(;;)
    15     {
    16         cin>>ch;
    17         cin>>c;
    18         if(ch=='$') break;
    19         else if(ch=='#')
    20         {
    21             s=c;
    22             if(a[s]=="") a[s]=s;//如果s没有爹,那么就只能让s叫自己爹了 
    23         }
    24         else if(ch=='+') a[c]=s;
    25         else cout<<c<<" "<<find(c)<<endl;
    26     }
    27     return 0;
    28 }
  • 相关阅读:
    1005: [HNOI2008]明明的烦恼
    1006: [HNOI2008]神奇的国度
    1007: [HNOI2008]水平可见直线
    1011: [HNOI2008]遥远的行星
    1025: [SCOI2009]游戏
    HTTP1.0和HTTP1.1的区别
    各排序算法的时间复杂度和空间复杂度
    换钱最少货币数
    矩阵的最小路径和
    背包问题
  • 原文地址:https://www.cnblogs.com/TFLS-gzr/p/10544118.html
Copyright © 2011-2022 走看看