質問C:COVID-19

質問C:COVID-19

トピックの説明:
2020年には、新しい冠状動脈性肺炎が世界を席巻します。
中国は決して諦めないという方針を採用し、常に国民の生命の安全を第一に考え、全世界から高い評価を得ているすべての市民の生存権を断固として擁護しています。
中国本土で実施されている疫学調査(以下「体液調整」といいます)の作業基準では、症例の密接な接触(以下「密接な接触」といいます)を追跡し、隔離とスクリーニングの作業を行う必要があります。 。

ここに画像の説明を挿入
南京のケースは家庭教師クラスの教師であるため、彼が教えた英語の家庭教師クラスのバスケットボールの家庭教師クラスの生徒と彼らが接触する人々を調査する必要があります。
ある大学にはnの学生クラブがあることが知られています。学生クラブの人事活動は頻繁に交換されるため、1人がウイルスに感染すると、クラブの全員と参加するクラブの全員がウイルスに感染する可能性があります。感染しているので、これらの人々は感染します。分離とテスト。
私たちは最初の感染者を患者0と呼ぶことに慣れています。感染者が0番の学校を卒業した後、最終的に何人の生徒が隔離されるかを調べてください。

入力
入力には、複数のテストケースセットが含まれています。各テストケースについて、最初の行には2つの整数nとmが含まれています。ここで、nは学校の生徒数を表し、mはクラブの数を表します。0 <n≤30000および0≤m≤1000であると仮定します。各学生には0からn-1までの番号が付けられています。次はm行です。各行の先頭には、クラブの学生数を示す整数kがあり、次にクラブの学生数を示すk整数があります。最後のテストケース、n = 0、m = 0は、入力の終わりを示します。
出力
データの各グループに対応して、0番目の学生が感染した後にウイルスに感染した学生の数を示す整数を含む1行を出力します。

サンプル入力
10 2
3 0 1 2
5 2 4 5 6 7

120 5
5 8 12 13 17 20
2 4 6
3 0 2 4
2 99 2
8 0 4 8 10 12 13 14 15

1 0

0 0

出力例
7
13
1

プロンプト
:最初のサンプルグループでは、10人の学生と2つのクラブが0 1 2に感染し、2番目のグループは4 5 6 7に感染しました。したがって、合計0 1 2 4 5 67と合計7人々は隔離されました。

この問題について、著者は問題を解決するために次の2つのアイデアを示します。(今回は、
方法1のアイデアとコードを更新します)方法1:各学生をセットの要素と見なし、マージチェックセットを使用して同じクラブの学生をマージします。すべてのマージが完了したら、Find()関数を使用して番号0の学生のルートノードを検索し、番号0の学生のルートノードのNum []を出力します。(ここに要約があります。特定の操作についてはコード1を参照してください)。

#include <stdio.h>

#define MAX 30001//学校学生人数n最多为30000。

int parent[MAX];//定义一个全局数组parent[],用来记录每个元素的根结点。
int Num[MAX];//定义一个全局数组Num[],用来记录根结点所在集合的元素个数。

/*初始化操作*/
void init(int n)
{
    
    
	int i;
	for(i=0;i<n;i++)
	{
    
    
		parent[i]=i;//将每个结点的父结点设置成自己(学生从0——n-1编号)。
		Num[i]=1;//将每个结点所在集合的元素个数设置为1。
	}
} 

/*查询元素的根结点操作*/
int Find(int i)
{
    
    
	if(parent[i]==i)//如果该元素的父结点就是其自己,则说明该元素为根结点,返回该元素的编号。
	 return i;
	else
	/*否则递归地去寻找该元素的根结点,
	递归操作顺便把从根到该结点路径上的所有结点都直接放到根节点下。*/
	 return parent[i]=Find(parent[i]);//压缩路径。
	 //补充:压缩路径的好处:有可能降低了树高,提高以后的查询效率。
}

/*集合合并操作*/
/*找到元素a的根结点A,元素b的根结点B,
如果元素a与元素b的根结点不同,则将A的父结点设置为B,并且更新以B为根结点的集合元素个数。*/
void Union(int a,int b)
{
    
    
	int A=Find(a);
	int B=Find(b);
    if(A!=B)
    {
    
    
    	parent[A]=B;
    	Num[B]+=Num[A];
	}
}

int main(int argc, char *argv[]) {
    
    
	int n,m,i,j,k,x,y;
	scanf("%d%d",&n,&m);//输入学校学生人数n和社团个数m。
	while(n!=0||m!=0)//输入结束条件n=0,m=0。
  {
    
     
    i=1;//初始化i为1.
    init(n);//对n个集合进行初始化(学生编号0——n-1,一开始将每个学生看成互不相交的单元素集合)
    
	while(i<=m)//m个社团。
	{
    
    
		scanf("%d%d",&k,&x);//输入社团人数k,和该社团中的第一个学生编号x。
		for(j=1;j<k;j++)//剩下k-1个该社团的学生,所以进行k-1次循环。
		{
    
    
			scanf("%d",&y);//输入该社团中的一个学生编号。
			Union(x,y);//将该生与第一个学生所在的集合进行合并操作。
		}
		i++;
	}
	int zero_root=Find(0);//找到编号为0的学生的根结点
	
	/*如果输入的社团个数为0,则输出1。
	举例:如果学校学生人数为1000,0个社团,0号学生感染了,则最后染病的学生人数为1。*/
	if(m==0)
	 printf("1");
	else//否则,输出编号为0的学生的根结点所在集合的个数。
	 printf("%d\n",Num[zero_root]);
	
	scanf("%d%d",&n,&m);
  }
  	return 0;
}

上記は最初の方法のアイデアとコードであり、2番目のソリューションは次回更新されます。友達、問題を解決するためのより良いアイデア、質問、提案があれば、コメントエリアで教えてください。この共有は以上です。ご覧いただきありがとうございます。

おすすめ

転載: blog.csdn.net/qq_46139801/article/details/113184509