浙江科技学院3.2日天梯赛初赛-----题解

1-1 N个数求和 (20 分)

本题的要求很简单,就是求N个数字的和。麻烦的是,这些数字是以有理数分子/分母的形式给出的,你输出的和也必须是有理数的形式。

输入格式:

输入第一行给出一个正整数N(≤100)。随后一行按格式a1/b1 a2/b2 ...给出N个有理数。题目保证所有分子和分母都在长整型范围内。另外,负数的符号一定出现在分子前面。

输出格式:

输出上述数字和的最简形式 —— 即将结果写成整数部分 分数部分,其中分数部分写成分子/分母,要求分子小于分母,且它们没有公因子。如果结果的整数部分为0,则只输出分数部分。

输入样例1:

5
2/5 4/15 1/30 -2/60 8/3

输出样例1:

3 1/3

输入样例2:

2
4/3 2/3

输出样例2:

2

输入样例3:

3
1/3 -1/6 1/8

输出样例3:

7/24

题目意思很简单,输入n个分数,输出他们的和即可。

 

思路:先通分,判断通风和后是不是假分数,如果是,提取出整数变成假分数,然后记得如果整数部分为0舍弃掉0。

 

按照通分方法进行即可,但如果直接求所有分母公倍数,再算分子的话,会有一个测试点无法通过,因为分母相乘会超出上线,所以应该一个数一个数相加,求和的同时约分。

 

还有就是可能会出现浮点数错误,就是在求gcd的时候对0取余了

#include
#include
#include
#include
#include
#include
#include
#include //有些用不到,个人习惯 
#include
#include
#include 
#define NNN 105
using namespace std;

long long gys(long long a,long long b){
    long long m,n,temp;
        if(a>b){
            temp=a;
            a=b;
            b=temp;
        }
        m=a;
        n=b;
        while(n!=0){   //防止出现浮点数错误
            temp=m%n;
            m=n;
            n=temp;
        }
        return m;
}


long long gbs(long long x,long long y){
	long long t=gys(x,y);
	return(x*y/t);
}

int main(void){
	
	long long num;
	long long a[NNN],b[NNN];
	int i;
	
	scanf("%lld",&num);
	
	for(i=1;i<=num;i++) scanf("%lld/%lld",&a[i],&b[i]);
	
	long long t1=0,t2=1,t=0;//t1分子,t2分母, 
		
	t1=0,t2=1;

	for(i=1;i<=num;i++){
		int temp1=t2;
		
		t2=gbs(t2,b[i]);
		t1=t1*(t2/temp1)+a[i]*(t2/b[i]);
		
		t+=t1/t2,t1=t1%t2;
		
		int temp2=gys(t1,t2);
		
		t1=t1/temp2,t2=t2/temp2;
	}
	    
	if(t1%t2==0) cout<<(t1/t2+t); //约分后t1,t2还在 
	
    else{
		if(t!=0)
		    cout<

1-2 比较大小 (10 分)

本题要求将输入的任意3个整数从小到大输出。

输入格式:

输入在一行中给出3个整数,其间以空格分隔。

输出格式:

在一行中将3个整数从小到大输出,其间以“->”相连。

输入样例:

4 2 8

输出样例:

2->4->8

 

类库就是垃圾,我就算wrong一千发我也要手写快排。

嗯,真香。

sort函数的具体用法可以看下面的博客

https://blog.csdn.net/qq_30587589/article/details/84098333

#include
#include
#include
using namespace std;

int main()
{
	int num[3];
	for (int i = 0; i < 3; i++) {
		cin >> num[i];
	}
	sort(num,num + 3);//没什么好说的,快排天下第一
	cout << num[0] << "->" << num[1] << "->" << num[2] << endl;
	return 0;
}

1-3 A-B (20 分)

本题要求你计算AB。不过麻烦的是,AB都是字符串 —— 即从字符串A中把字符串B所包含的字符全删掉,剩下的字符组成的就是字符串AB

输入格式:

输入在2行中先后给出字符串AB。两字符串的长度都不超过104,并且保证每个字符串都是由可见的ASCII码和空白字符组成,最后以换行符结束。

输出格式:

在一行中打印出AB的结果字符串。

输入样例:

I love GPLT!  It's a fun game!

aeiou

输出样例:

I lv GPLT!  It's  fn gm!

建立两个string,然后利用string.fing开始遍历B字符串,找到一个string.erase一个,搞定

 

#include
#include
#include
#include
#include
using namespace std;

int main()
{
	string a, b;
	int p;
	int len_a, len_b;
	getline(cin, a);//因为有空格所以得用getline
	getline(cin, b);

	len_a = a.length();
	len_b = b.length();

	for (int i = 0; i < len_b; i++) {//遍历b字符串,其实还可以加个标记优化下时间
		p = a.find(b[i]);
		if (p != a.npos) {//如果找到了
			a.erase(p, 1);//删除这个字符
			i--;//因为删除了一个,for循环又要i++,所以这里要i--,不然会跳过一个了
		}
	}
	cout << a << endl;
	return 0;
}

当然更简单的就是用cmp

#include  
using namespace std;
int main()
{
	map mp;
	string A,B;
	getline(cin,A);
	getline(cin,B);
	int l1=A.size();
	int l2=B.size();
	for(int i=0;i

1-4 计算指数 (5 分)

真的没骗你,这道才是简单题 —— 对任意给定的不超过10的正整数n,要求你输出2n。不难吧?

输入格式:

输入在一行中给出一个不超过10的正整数n

输出格式:

在一行中按照格式 2^n = 计算结果 输出2n的值。

输入样例:

5

输出样例:

2^5 = 32

 

这题也是没什么好说的,直接用pow函数算出结果即可


 

#include

#include

#include

using namespace std;



int main()

{

int n, ans;

cin >> n;

ans = pow(2, n);

cout << "2^" << n << " = " << ans << endl;

return 0;

}



1-5 计算阶乘和 (10 分)

对于给定的正整数N,需要你计算 S=1!+2!+3!+...+N!

输入格式:

输入在一行中给出一个不超过10的正整数N

输出格式:

在一行中输出S的值。

输入样例:

3

输出样例:

9

 

两个循环搞定

#include
#include
#include
using namespace std;

int main()
{
	int n;
	int temp, ans = 0;
	cin >> n;
	for (int i = 1; i <= n; i++) {
		temp = 1;//注意temp是1,不是0
		for (int j = 1; j <= i; j++) {
			temp *= j;
		}
		ans += temp;
	}
	cout << ans << endl;
	return 0;
}

1-6 简单题 (5 分)

这次真的没骗你 —— 这道超级简单的题目没有任何输入。

你只需要在一行中输出事实:This is a simple problem. 就可以了。

 

别告诉我你不会,不会就退群吧。

1-7 跟奥巴马一起画方块 (15 分)

美国总统奥巴马不仅呼吁所有人都学习编程,甚至以身作则编写代码,成为美国历史上首位编写计算机代码的总统。2014年底,为庆祝“计算机科学教育周”正式启动,奥巴马编写了很简单的计算机代码:在屏幕上画一个正方形。现在你也跟他一起画吧!

输入格式:

输入在一行中给出正方形边长N(3≤N≤21)和组成正方形边的某种字符C,间隔一个空格。

输出格式:

输出由给定字符C画出的正方形。但是注意到行间距比列间距大,所以为了让结果看上去更像正方形,我们输出的行数实际上是列数的50%(四舍五入取整)。

输入样例:

10 a

输出样例:

aaaaaaaaaa
aaaaaaaaaa
aaaaaaaaaa
aaaaaaaaaa
aaaaaaaaaa
#include
#include
#include
#include

using namespace std;

int main(void)
{
	int n;
	char a;
	
	scanf("%d %c",&n,&a);
	
	int i,j;
	
	for(i=1;i<=(n+1)/2;i++)  //二重循环,注意到四舍五入行号故 (n+1)/2
	{
		for(j=1;j<=n;j++)
		{
			printf("%c",a);
		}
		printf("\n");
	}
	return 0;
}

1-8 查验身份证 (15 分)

一个合法的身份证号码由17位地区、日期编号和顺序编号加1位校验码组成。校验码的计算规则如下:

首先对前17位数字加权求和,权重分配为:{7,9,10,5,8,4,2,1,6,3,7,9,10,5,8,4,2};然后将计算的和对11取模得到值Z;最后按照以下关系对应Z值与校验码M的值:

Z:0 1 2 3 4 5 6 7 8 9 10

M:1 0 X 9 8 7 6 5 4 3 2

现在给定一些身份证号码,请你验证校验码的有效性,并输出有问题的号码。

输入格式:

输入第一行给出正整数N(≤100)是输入的身份证号码的个数。随后N行,每行给出1个18位身份证号码。

输出格式:

按照输入的顺序每行输出1个有问题的身份证号码。这里并不检验前17位是否合理,只检查前17位是否全为数字且最后1位校验码计算准确。如果所有号码都正常,则输出All passed

输入样例1:

4
320124198808240056
12010X198901011234
110108196711301866
37070419881216001X

输出样例1:

12010X198901011234
110108196711301866
37070419881216001X

输入样例2:

2
320124198808240056
110108196711301862

输出样例2:

All passed

题目就是要你求输入数字的加权求和,然后求余,根据表和最后一位的校验码进行比较判断是否身份证有问题

 

注意事项两个,一是记得判断前十七位有X的话也是错误的,一样需要输出,二是记得X别写错小写。

 

 

#include
#include
#include
#include
using namespace std;

int main(void)
{
	char ide[105][105];
	int a[105]={7,9,10,5,8,4,2,1,6,3,7,9,10,5,8,4,2};
	char b[105] = { '1','0','X','9','8','7','6','5','4','3','2'}; 
	int flag[105]={0};
	int n;
	
	cin>>n;
	
	int i,j;
	
	memset(flag,0,sizeof(flag));
	
	for(i=1;i<=n;i++)
	{
		for(j=0;j<=17;j++)
		{
			cin>>ide[i][j];
			
			if((ide[i][j]<'0'||ide[i][j]>'9')&&j!=17) //注意括号,否则会错误, 
		    {
		    	flag[i]=1;  //flag[i]=1表示第i个号码前十七位有X 
			}
		}
	}
	
	int k=0;
	
	for(i=1;i<=n;i++)
	{
		int sum=0;
		
		for(j=0;j<=16;j++) 
		    sum+=(int(ide[i][j])-48)*a[j]; //加权求和, 
			
		int t1=sum%11;
		
		if(ide[i][17]!=b[t1]||flag[i]==1)
		{
			for(j=0;j<=17;j++)
			{
				cout<

1-9 家庭房产 (25 分)

给定每个人的家庭成员和其自己名下的房产,请你统计出每个家庭的人口数、人均房产面积及房产套数。

输入格式:

输入第一行给出一个正整数N(≤1000),随后N行,每行按下列格式给出一个人的房产:

编号 父 母 k 孩子1 ... 孩子k 房产套数 总面积

其中编号是每个人独有的一个4位数的编号;分别是该编号对应的这个人的父母的编号(如果已经过世,则显示-1);k(0≤k≤5)是该人的子女的个数;孩子i是其子女的编号。

输出格式:

首先在第一行输出家庭个数(所有有亲属关系的人都属于同一个家庭)。随后按下列格式输出每个家庭的信息:

家庭成员的最小编号 家庭人口数 人均房产套数 人均房产面积

其中人均值要求保留小数点后3位。家庭信息首先按人均面积降序输出,若有并列,则按成员编号的升序输出。

输入样例:

10
6666 5551 5552 1 7777 1 100
1234 5678 9012 1 0002 2 300
8888 -1 -1 0 1 1000
2468 0001 0004 1 2222 1 500
7777 6666 -1 0 2 300
3721 -1 -1 1 2333 2 150
9012 -1 -1 3 1236 1235 1234 1 100
1235 5678 9012 0 1 50
2222 1236 2468 2 6661 6662 1 300
2333 -1 3721 3 6661 6662 6663 1 100

输出样例:

3
8888 1 1.000 1000.000
0001 15 0.600 100.000
5551 4 0.750 100.000

并查集题目,就是对一类元素进行划分,没有先后顺序,只有属于不属于,可以理解为分为好几个集合。

 

如果毫无概念或者从来没了解过的话建议先去看下《啊哈算法》或者自己百度相关知识来进行学习。

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include 
#define NNN 105

#define maxn 10050

using namespace std;

int vis[maxn],jud[maxn]; /* vis用来记录是否被归类过,也用来判断是否存在*/ 
int f[maxn];             //jud用来记录每个家庭 
                         //f 并查集 

struct node{

	double house,area;              

	int id,num;

};

bool cmp(node a,node b){
	if(a.area!=b.area)
	
		return a.area>b.area;
		
	return a.idy)
		    f[x]=y;
		else
		    f[y]=x; 
	}
}

int main(void){
	int num,k;
	int i,j;

	node a[maxn]; //a[i]记录每个小家庭的信息 
	node b[maxn]; //b[i]记录每个类的平均信息 
	node c[maxn]; //c[i]记录每个类的总和 
	
	memset(vis,0,sizeof(vis));
	memset(jud,0,sizeof(jud));
	
	init(); /*并查集初始化 */ 
	
	cin>>num;   
	
	int faf,mom;
	
	for(i=0;i>a[i].id>>faf>>mom;
		
		vis[a[i].id]=1;
		
		if(faf!=-1){                      /* 开始时根据题目要求输入的民工三连 */ 
		    unio(a[i].id,faf);            /*vis[]=1表示已经被归类过了*/ 
		    vis[faf]=1;
	    }
	    if(mom!=-1){
	    	unio(a[i].id,mom);
	    	vis[mom]=1;
		}
		
		cin>>k;
		                                 /* 对于每个人,他父母和他孩子属于一个家庭
										    所以我们把他们进行归类*/
										//所有有亲属关系的人都属于同一个家庭,所以这样归类没毛病 
		int u;
		
		for(j=1;j<=k;j++){
			 
			cin>>u;
			if(u!=-1){
			    unio(u,a[i].id);
			    vis[u]=1;
			}
		}
		
		cin>>a[i].house>>a[i].area;
	} 
	  /*下面的所有//cout之类的都是做题时候留下的遗珠
	    为了能够让你们区分,所以我决定用/* (#滑稽)*/ 
	
  //  double t1=0,t2=0;
	
	for(i=0;i

 

1-10 最长对称子串 (25 分)

对给定的字符串,本题要求你输出最长对称子串的长度。例如,给定Is PAT&TAP symmetric?,最长对称子串为s PAT&TAP s,于是你应该输出11。

输入格式:

输入在一行中给出长度不超过1000的非空字符串。

输出格式:

在一行中输出最长对称子串的长度。

输入样例:

Is PAT&TAP symmetric?

输出样例:

11

 

 

暴力遍历出所有的情况,然后统计得出最优解

读入父字符串a,然后b字符串用来复制部分a父字符串,利用双循环可以复制所有部分的a字符串,得到所有情况。然后每一次复制后,再把b字符串复制给c备份字符串,再把b字符串反转,如果反转后的子字符串和备份字符串相等,那就可以记下这个部分字符串的长度了。

#include
#include
#include
#include
#include
using namespace std;

int main()
{
	string a, b, c;//父字符串,子字符串,备份字符串
	int ans = 0;
	int len_a, len_b, len_c;

	getline(cin, a);//父字符串读取
	len_a = a.length();//获取父字符串长度

	for (int i = 0; i < len_a; i++) {
		for (int j = len_a - 1; j >= i; j--) {
			b = a.substr(i, j + 1);//复制(从下标i开始的j+1个字符)部分父字符串
			c = b;//再把子字符串复制给 备份字符串
			reverse(b.begin(), b.end());//把子字符串反转
			if (c == b) {//如果反转后的子字符串和备份字符串相等
				if (ans < b.length()) {
					ans = b.length();
				}
			}
		}
	}
	cout << ans << endl;
	return 0;
}

[原题链接](https://pintia.cn/problem-sets/1099928968171696128/problems/1099930328292208640)

没有人没抢过红包吧…… 这里给出N个人之间互相发红包、抢红包的记录,请你统计一下他们抢红包的收获。

 

输入格式:

 

输入第一行给出一个正整数N(≤10000),即参与发红包和抢红包的总人数,则这些人从1到N编号。随后N行,第i行给出编号为i的人发红包的记录,格式如下:

 

K N​1 P​1​​ ⋯NK P​K

其中K(0≤K≤20)是发出去的红包个数,N​i是抢到红包的人的编号,P​i>0)是其抢到的红包金额(以分为单位)。注意:对于同一个人发出的红包,每人最多只能抢1次,不能重复抢。

 

输出格式:

 

按照收入金额从高到低的递减顺序输出每个人的编号和收入金额(以元为单位,输出小数点后2位)。每个人的信息占一行,两数字间有1个空格。如果收入金额有并列,则按抢到红包的个数递减输出;如果还有并列,则按个人编号递增输出。

输入样例:

 

10

3 2 22 10 58 8 125

5 1 345 3 211 5 233 7 13 8 101

1 7 8800

2 1 1000 2 1000

2 4 250 10 320

6 5 11 9 22 8 33 7 44 10 55 4 2

1 3 8800

2 1 23 2 123

1 8 250

4 2 121 4 516 7 112 9 10

输出样例:

 

1 11.63

2 3.63

8 3.63

3 2.11

7 1.69

6 -1.67

9 -2.18

10 -3.26

5 -3.26

4 -12.32

难点:如果不偷懒用sort之类的排序函数的话要手写快排可能有点烦?

#include
#include
#include
#include
using namespace std;
struct note
{
	int num,id;	//num表示抢到的红包个数,id表示编号
	double sum;
}a[10002];	//结构体数组a存贮每个人的编号,抢到的红包个数和收入金额
bool cmp(note a,note b)
{
    if(a.sum!=b.sum)
        return a.sum>b.sum;	//按收入金额降序排序
    else if(a.num!=b.num)
        return a.num>b.num;	//如果收入金额相同,则按照收到的红包个数降序排序
    else
        return a.id

[原题链接](https://pintia.cn/problem-sets/1099928968171696128/problems/1099931900380262400)

一个整数“犯二的程度”定义为该数字中包含2的个数与其位数的比值。如果这个数是负数,则程度增加0.5倍;如果还是个偶数,则再增加1倍。例如数字-13142223336是个11位数,其中有3个2,并且是负数,也是偶数,则它的犯二程度计算为:3/11×1.5×2×100%,约为81.82%。本题就请你计算一个给定整数到底有多二。

 

输入格式:

 

输入第一行给出一个不超过50位的整数N。

 

输出格式:

 

在一行中输出N犯二的程度,保留小数点后两位。

 

输入样例:

 

-13142223336

输出样例:

 

81.82%

 

难点:输入的整数有50位,所以我采用了字符串数组解决(不太清楚long long int够不够),除此之外好像没什么要注意的

 

#include
#include
int main()
{
	int num,total,i;
	double out;
	char s[52];	//储存输入的整数
	while(scanf("%s",s)!=EOF)
	{
		num=0;	//2的个数
		total=0;	//输入的整数的总位数
		out=1;	//表示犯二程度
		if(s[0]=='-')	//确定输入的数为整数还是负数
		{
			out*=1.5;
			i=1;
		}	//如果输入的数为负数,则字符串开头为符号位,也就是负号,故数字位从第二位开始,也就是s[1]
		else	i=0;
		while(s[i]!='\0')
		{
			if(s[i]=='2')	num++;
			total++;
			i++;	
		}	//一位位读取字符串数组
		if((s[i-1]-'2')%2==0)	out*=2;
		out=out*100*num/total;
		printf("%.2lf%%",out);
		memset(s,'\0',sizeof(s));	//初始化字符串数组s
	}
	return 0;
}

[原题链接](https://pintia.cn/problem-sets/1099928968171696128/problems/1099931900384456704)

微博上有个自称“大笨钟V”的家伙,每天敲钟催促码农们爱惜身体早点睡觉。不过由于笨钟自己作息也不是很规律,所以敲钟并不定时。一般敲钟的点数是根据敲钟时间而定的,如果正好在某个整点敲,那么“当”数就等于那个整点数;如果过了整点,就敲下一个整点数。另外,虽然一天有24小时,钟却是只在后半天敲1~12下。例如在23:00敲钟,就是“当当当当当当当当当当当”,而到了23:01就会是“当当当当当当当当当当当当”。在午夜00:00到中午12:00期间(端点时间包括在内),笨钟是不敲的。

 

下面就请你写个程序,根据当前时间替大笨钟敲钟。

 

输入格式:

 

输入第一行按照hh:mm的格式给出当前时间。其中hh是小时,在00到23之间;mm是分钟,在00到59之间。

 

输出格式:

 

根据当前时间替大笨钟敲钟,即在一行中输出相应数量个Dang。如果不是敲钟期,则输出:

Only hh:mm.  Too early to Dang.

其中hh:mm是输入的时间。

难点:输入和输出的时候时间的格式是hh:mm,也就是说是有前置0的,例如01:05(这可能是唯一的坑点了,有两种解决方案,一种是用字符串数组读入,一种是以整数形式读入)

还有记得端点值记得判断

输入样例1:

 

19:05

输出样例1:

 

DangDangDangDangDangDangDangDang

输入样例2:

 

07:05

输出样例2:

 

Only 07:05.  Too early to Dang.

代码

#include

int main()
{
	int n;
	char a[5]="Dang",s[6];	//此段代码为用字符串数组读入的写法
	while(scanf("%s",s)!=EOF)
	{
		if(s[0]=='0'||(s[0]=='1'&&(s[1]<'2'||(s[1]=='2'&&s[3]=='0'&&s[4]=='0'))))	printf("Only %s.  Too early to Dang.\n",s);	//判断时间是否要敲钟
		else
		{
			n=0;	//初始化n,n代表要敲几次钟
			if(s[3]>'0'||s[4]>'0')	n++;	//根据题目要求,若超过整点,则敲钟数+1
			n+=(s[0]-'1')*10+(s[1]-'2');
			while(n--)
			{
				printf("%s",a);
			}
			printf("\n");
		}
	}
	return 0;
}

[原题链接](https://pintia.cn/problem-sets/1099928968171696128/problems/1099931900392845312)

划拳是古老中国酒文化的一个有趣的组成部分。酒桌上两人划拳的方法为:每人口中喊出一个数字,同时用手比划出一个数字。如果谁比划出的数字正好等于两人喊出的数字之和,谁就输了,输家罚一杯酒。两人同赢或两人同输则继续下一轮,直到唯一的赢家出现。

 

下面给出甲、乙两人的酒量(最多能喝多少杯不倒)和划拳记录,请你判断两个人谁先倒。

 

输入格式:

 

输入第一行先后给出甲、乙两人的酒量(不超过100的非负整数),以空格分隔。下一行给出一个正整数N(≤100),随后N行,每行给出一轮划拳的记录,格式为:

 

甲喊 甲划 乙喊 乙划

其中喊是喊出的数字,划是划出的数字,均为不超过100的正整数(两只手一起划)。

 

输出格式:

 

在第一行中输出先倒下的那个人:A代表甲,B代表乙。第二行中输出没倒的那个人喝了多少杯。题目保证有一个人倒下。注意程序处理到有人倒下就终止,后面的数据不必处理。

输入样例:

 

1 1

6

8 10 9 12

5 10 5 10

3 8 5 12

12 18 1 13

4 16 12 15

15 1 1 16

输出样例:

 

A

1

难点:注意一下当一个人喝到之后,两人喝了多少杯的计数就停止,除此外好像没什么坑的

代码:

#include
struct note
{
	int sum,num,a,b;	//sum表示最多能喝几杯,num记录已经喝的杯数,a表示喊的数,b表示划的数 
}p[2];	//结构体数组,p[0]表示甲,p[1]表示乙 
int main()
{
	int flag,n;
	while(scanf("%d%d",&p[0].sum,&p[1].sum)!=EOF)	
	{
		p[0].num=p[1].num=0;
		flag=0;	//flag为1则说明已经有人喝倒了 
		scanf("%d",&n);
		while(n--)
		{
			scanf("%d%d%d%d",&p[0].a,&p[0].b,&p[1].a,&p[1].b);
			if(flag==1)	continue;	//如果有人喝倒则停止,但数据还是要读取完的不然有多组数据的时候会影响下一组数据的读入 
			if(p[0].b==p[0].a+p[1].a&&p[1].b!=p[0].a+p[1].a)	p[0].num++;
			else if(p[1].b==p[0].a+p[1].a&&p[0].b!=p[0].a+p[1].a)	p[1].num++;
			if(p[0].num>p[0].sum)
			{
				printf("A\n%d\n",p[1].num);
				flag=1;
			}
			else if(p[1].num>p[1].sum)
			{
				printf("B\n%d\n",p[0].num);
				flag=1;
			}
		}
	}
	return 0;
}

[原题链接](https://pintia.cn/problem-sets/1099928968171696128/problems/1099931900392845313)

输入格式:

 

输入第一行给出一个正整数N(≤100),是已知朋友圈的个数;随后N行,每行首先给出一个正整数K(≤1000),为朋友圈中的人数,然后列出一个朋友圈内的所有人——为方便起见,每人对应一个ID号,为5位数字(从00000到99999),ID间以空格分隔;之后给出一个正整数M(≤10000),为待查询的人数;随后一行中列出M个待查询的ID,以空格分隔。

 

注意:没有朋友的人可以是根本没安装“朋友圈”,也可以是只有自己一个人在朋友圈的人。虽然有个别自恋狂会自己把自己反复加进朋友圈,但题目保证所有K超过1的朋友圈里都至少有2个不同的人。

 

输出格式:

 

按输入的顺序输出那些帅到没朋友的人。ID间用1个空格分隔,行的首尾不得有多余空格。如果没有人太帅,则输出No one is handsome。

 

注意:同一个人可以被查询多次,但只输出一次。

 

输入样例1:

 

3

3 11111 22222 55555

2 33333 44444

4 55555 66666 99999 77777

8

55555 44444 10000 88888 22222 11111 23333 88888

输出样例1:

 

10000 88888 23333

输入样例2:

 

3

3 11111 22222 55555

2 33333 44444

4 55555 66666 99999 77777

4

55555 44444 22222 11111

输出样例2:

 

No one is handsome

 

难点:第一点,有些人的朋友圈如果只有一个人,那么也算是没朋友。第二点,查询的时候一个id号可能会被查询多次,但最多只输出一次。

#include
#include
int vis[100000];	//vis记录某个编号是否有被访问过,及该编号是否有朋友 

int main()
{
	int n,m,x,flag,i;
	char id[6];
	while(scanf("%d",&n)!=EOF)
	{
		memset(vis,0,sizeof(vis));	//初始化vis 
		while(n--)
		{
			scanf("%d",&m);
			flag=0;	 
			if(m==1)	flag=1;	//特判,若朋友圈只有一个人,则该人也算在没朋友的行列中 
			while(m--)
			{
				scanf("%s",id);	//储存读入的数据 
				x=(id[0]-'0')*10000+(id[1]-'0')*1000+(id[2]-'0')*100+(id[3]-'0')*10+(id[4]-'0');	//将读入的数据转换成整型 
				if(vis[x]==0&&flag==0)	vis[x]=1;
			}
		}
		scanf("%d",&i);
		flag=0;	//特判,此处的flag记录是否有人没朋友 
		while(i--)
		{
			scanf("%s",id);
			x=(id[0]-'0')*10000+(id[1]-'0')*1000+(id[2]-'0')*100+(id[3]-'0')*10+(id[4]-'0');
			if(vis[x]==0)
			{
				if(flag==0)
				{
					flag=1;	//若有人没有朋友则flag为1 
					printf("%05d",x);
				}
				else	printf(" %05d",x);
				vis[x]=1;
			}
		}
		if(flag==0)	printf("No one is handsome");	//若flag为0,则说明没有人没有朋友 
		printf("\n");
	}
	return 0;
}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

你可能感兴趣的:(基础算法)