PTA2016年天梯赛题目整理

题目按分数值递增

简单题仅贴思路和关键代码

7-2 I Love GPLT(5 分)

这道超级简单的题目没有任何输入。

你只需要把这句很重要的话 —— I Love GPLT ——竖着输出就可以了。

所谓“竖着输出”,是指每个字符占一行(包括空格),即每行只能有1个字符和回车

printf("I\n"); printf(" \n");



7-5 是不是太胖了(5 分)

据说一个人的标准体重应该是其身高(单位:厘米)减去100、再乘以0.9所得到的公斤数。已知市斤是公斤的两倍。现给定某人身高,请你计算其标准体重应该是多少?(顺便也悄悄给自己算一下吧……)

输入格式:

输入第一行给出一个正整数H(100 < H  300),为某人身高。

输出格式:

在一行中输出对应的标准体重,单位为市斤,保留小数点后1位。

输入样例:

169

输出样例:

124.2
wight = (h-100)*0.9*2;




7-4 判断素数(10 分)

本题的目标很简单,就是判断一个给定的正整数是否素数。

输入格式:

输入在第一行给出一个正整数N 10),随后N行,每行给出一个小于231的需要判断的正整数。

输出格式:

对每个需要判断的正整数,如果它是素数,则在一行中输出Yes,否则输出No

输入样例:

2
11
111

输出样例:

Yes
No
#include
#include
int main(){
int n, i, flag;
long long x;
scanf("%d", &n);
while(n--)
{
scanf("%lld", &x);
flag =1;
for(i = 2; i <= sqrt(x); i++)
{
if(x % i == 0)
{
flag =0;
break;
}
}
if(x == 1 || flag == 0)
printf("No\n");
else
printf("Yes\n");
}
return0;
}
//素数:除1以外只能被其自身整除,注意1不是素数,2是素数



7-7 到底是不是太胖了(10 分)

据说一个人的标准体重应该是其身高(单位:厘米)减去100、再乘以0.9所得到的公斤数。真实体重与标准体重误差在10%以内都是完美身材(即 | 真实体重  标准体重 | < 标准体重×10%)。已知市斤是公斤的两倍。现给定一群人的身高和实际体重,请你告诉他们是否太胖或太瘦了。

输入格式:

输入第一行给出一个正整数N 20)。随后N行,每行给出两个整数,分别是一个人的身高H(120 < H < 200;单位:厘米)和真实体重W(50 < W  300;单位:市斤),其间以空格分隔。

输出格式:

为每个人输出一行结论:如果是完美身材,输出You are wan mei!;如果太胖了,输出You are tai pang le!;否则输出You are tai shou le!

输入样例:

3
169 136
150 81
178 155

输出样例:

You are wan mei!
You are tai shou le!
You are tai pang le!
#include
#include
int n, a, b, c,i,j;
main()
{
scanf("%d", &n);
for (i = 1; i <= n; i++)
{
scanf("%d %d", &a, &b);
c = (a - 100)*1.8;
if (fabs(b - c) < (c*0.1))
{
printf("You are wan mei!\n");
}
if ((fabs(b - c) >= (c*0.1)) && b < c)
{
printf("You are tai shou le!\n");
}
if ((fabs(b - c) >= (c*0.1)) && b > c)
{
printf("You are tai pang le!\n");
}
}
}



7-1 正整数A+B(15 分)

题的目标很简单,就是求两个正整数AB的和,其中AB都在区间[1,1000]。稍微有点麻烦的是,输入并不保证是两个正整数。

输入格式:

输入在一行给出AB,其间以空格分开。问题是AB不一定是满足要求的正整数,有时候可能是超出范围的数字、负数、带小数点的实数、甚至是一堆乱码。

注意:我们把输入中出现的第1个空格认为是AB的分隔。题目保证至少存在一个空格,并且B不是一个空字符串。

输出格式:

如果输入的确是两个正整数,则按格式A + B = 和输出。如果某个输入不合要求,则在相应位置输出?,显然此时和也是?

输入样例1:

123 456

输出样例1:

123 + 456 = 579

输入样例2:

22. 18

输出样例2:

? + 18 = ?

输入样例3:

-100 blabla bla...33

输出样例3:

? + ? = ?

#include
 #include
 #include
 using namespace std;
 int main(){
  char a[1001],b[1001];
  int c,d;
  bool flag1=true;
bool flag2=true;
cin>>a;
scanf(" ");
cin>>b;
  int len1=strlen(a);
  int len2=strlen(b);
  if(len1<1||len1>4)
  flag1=false;
  else{
  for(int i=0;i  
  if(a[i]<'0' || a[i]>'9'){
  flag1=false;
  break;
  }
  }
  }
  if(len2<1||len2>4)
  flag2=false;
  else{
  for(int i=0;i   if(b[i]<'0'||b[i]>'9'){
  flag2=false;
  break;
  }
  }
  }
  if(flag1&&flag2){
  c=0;d=0;
  for(int i=0;i   c=c*10+a[i]-'0';
  }
  for(int i=0;i   d=d*10+b[i]-'0';
  }
  if(c<1&&c>1000)
  flag1=false;
  if(d<1&&d>1000)
  flag2=false;
  }
  if(flag1)
  cout<   else
  cout<<"? ";
  cout<<"+ ";
  if(flag2)
  cout<   else
  cout<<"? ";
  cout<<"= ";
  if(flag1&&flag2)
  cout<   else
  cout<<"?";
 } 



7-3 谁先倒(15 分)

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

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

输入格式:

输入第一行先后给出甲、乙两人的酒量(不超过100的非负整数),以空格分隔。下一行给出一个正整数N100),随后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
int main(){
int a,b;
int n;
scanf("%d%d",&a,&b);
scanf("%d",&n);
int ahan,ahua,bhan,bhua;
int ac=0,bc=0;
while(n--){
scanf("%d%d%d%d",&ahan,&ahua,&bhan,&bhua);
if((ahan+bhan!=ahua && ahan+bhan!=bhua) || (ahan+bhan==ahua && ahan+bhan==bhua)){ //同赢或者同输
continue;
}
else if(ahan+bhan==ahua && ahan+bhan!=bhua){//甲输甲喝
ac++;
}
else if(ahan+bhan==bhua && ahan+bhan!=ahua){//乙输乙喝
bc++;
}
if(ac>a || bc>b){ //任意一个超过酒量倒下的就停止,继续输入下面的数据,但是不处理
while(n--){
scanf("%d%d%d%d",&ahan,&ahua,&bhan,&bhua);
}
break;
}
}
if(ac>a){
printf("A\n%d\n",bc);
}
else
printf("B\n%d\n",ac);
}



7-6 一帮一(15 分)

“一帮一学习小组”是中小学中常见的学习组织方式,老师把学习成绩靠前的学生跟学习成绩靠后的学生排在一组。本题就请你编写程序帮助老师自动完成这个分配工作,即在得到全班学生的排名后,在当前尚未分组的学生中,将名次最靠前的学生与名次最靠后的异性学生分为一组。

输入格式:

输入第一行给出正偶数N50),即全班学生的人数。此后N行,按照名次从高到低的顺序给出每个学生的性别(0代表女生,1代表男生)和姓名(不超过8个英文字母的非空字符串),其间以1个空格分隔。这里保证本班男女比例是1:1,并且没有并列名次。

输出格式:

每行输出一组两个学生的姓名,其间以1个空格分隔。名次高的学生在前,名次低的学生在后。小组的输出顺序按照前面学生的名次从高到低排列。

输入样例:

8
0 Amy
1 Tom
1 Bill
0 Cindy
0 Maya
1 John
1 Jack
0 Linda

输出样例:

Amy Jack
Tom Linda
Bill Maya
Cindy John
#include
#include
int main()
{
int sex[60],vis[60];
char name[60][10];
int N;
scanf("%d",&N);
for(int i=0;i scanf("%d%s",&sex[i],&name[i]);
}
memset(vis,0,sizeof(vis));
for(int i=0;i<=N/2;i++){
while(vis[i]==0){
int j=N-1;
while(sex[i]==sex[j] || vis[j]==1){
j--;
}
printf("%s %s\n",name[i],name[j]);
vis[i] = vis[j] = 1;
}
}
return 0;
}



7-1 到底有多二(15 分)

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

输入格式:

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

输出格式:

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

输入样例:

-13142223336

输出样例:

81.82%
#include
#include
int main(){
char num[101];
int len=0;
int elen=0;
double result,beishu=1;
    scanf("%s", &num);
    len = strlen(num);
    num[len] = '\0';
    for(int i=0;i     if(num[i]=='2')
elen++;
    }
if(num[0]=='-'){
if(num[len-1]=='2'||num[len-1]=='4'||num[len-1]=='6'||num[len-1]=='8'||num[len-1]=='0'){
beishu=(beishu+0.5)*2;
result=(double)elen/(len-1)*beishu*100;
}
else{
beishu=beishu+0.5;
result=(double)elen/(len-1)*beishu*100;
}
}
else{
if(num[len-1]=='2'||num[len-1]=='4'||num[len-1]=='6'||num[len-1]=='8'||num[len-1]=='0'){
beishu=beishu*2;
result=(double)elen/len*beishu*100;
}
else{
result=(double)elen/len*beishu*100;
}
}
printf("%.2lf%%\n",result);
}



7-4 帅到没朋友(20 分)

当芸芸众生忙着在朋友圈中发照片的时候,总有一些人因为太帅而没有朋友。本题就要求你找出那些帅到没有朋友的人。

输入格式:

输入第一行给出一个正整数N100),是已知朋友圈的个数;随后N行,每行首先给出一个正整数K1000),为朋友圈中的人数,然后列出一个朋友圈内的所有人——为方便起见,每人对应一个ID号,为5位数字(从00000到99999),ID间以空格分隔;之后给出一个正整数M10000),为待查询的人数;随后一行中列出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
自己的思路+百度--->改进后的:答案正确,但 跑分2分
大体思路:id数组存id,handsome数组存要查的id,输入一个id就让id数组中对应下标的值为1,以此来区别要查的id不在id数组中。要查的id查完就赋值为1,以免出现重复。
#include
#include
int main(){
int n,k,m;
int idd;
int id[100001];
int handsome[10001];
int c=0;
int zero;
scanf("%d",&n);
memset(id,0,sizeof(id));
while(n--){
scanf("%d",&k);
if(k==1){
scanf("%d",&idd);
zero=idd;
id[zero]=0;
}
else{
while(k--){
scanf("%d",&idd);
id[idd]=1;
}
}
}
int flag=0;
scanf("%d",&m);
for(int j=0;j scanf("%d",&handsome[j]);
if(id[handsome[j]]==0){
printf("%05d ",zero);
printf("%05d ",handsome[j]);
flag++;
id[handsome[j]]=1; 
}
}
if(flag==0)
printf("No one is handsome\n");
}
百度满分代码:
#include ///和这位大神学的万能头文件
using namespace std;
int a[1000000]= {0}; ///用一个能容下全部的人的数组来标每一个人是否有朋友
int main ()
{
    int n;///n个朋友圈
    cin>>n;
    for(int i=0; i     {
        int k;///朋友圈的人数
        cin>>k;
        for(int i=0; i         {
            int t;///朋友圈的每一个人
            cin>>t;
            if(k!=1)///判断朋友圈是否只有一个人 如果只有一个人则这个人没朋友
            {
                a[t]=1;
            }
        }
    }
    int m;///进行m次询问
    cin>>m;
    int flag=0;///来标记是否已经输出
    while(m--)
    {
        int key;
        cin>>key;
        if(a[key]==0)///这个人没朋友
        {
            if(flag==0)///标记否为第一个没朋友的人
            {
                flag++;
            }
            else printf(" ");
            printf("%05d",key);
            a[key]=1;///根据题意该热不可能在输出等价于已经有了朋友
        }
    }
    if(flag==0)
    {
        cout<<"No one is handsome"<     }
    return 0;
}

7-7 输出GPLT(20 分)

给定一个长度不超过10000的、仅由英文字母构成的字符串。请将字符重新调整顺序,按GPLTGPLT....这样的顺序输出,并忽略其它字符。当然,四种字符(不区分大小写)的个数不一定是一样多的,若某种字符已经输出完,则余下的字符仍按GPLT的顺序打印,直到所有字符都被输出。

输入格式:

输入在一行中给出一个长度不超过10000的、仅由英文字母构成的非空字符串。

输出格式:

在一行中按题目要求输出排序后的字符串。题目保证输出非空。

输入样例:

pcTclnGloRgLrtLhgljkLhGFauPewSKgt

输出样例:

GPLTGPLTGLTGLGLL
#include
#include
int main(){
char words[10001];
int len;
scanf("%s",&words);
len=strlen(words);
int g=0,p=0,l=0,t=0;
for(int i=0;i if(words[i]=='G'||words[i]=='g')
g++;
if(words[i]=='P'||words[i]=='p')
p++;
if(words[i]=='L'||words[i]=='l')
l++;
if(words[i]=='T'||words[i]=='t')
t++;
}
while(1){
if(g==0&&p==0&&l==0&&t==0)
break;
if(g>0){
printf("G");
g--;
}
if(p>0){
printf("P");
p--;
}
if(l>0){
printf("L");
l--;
}
if(t>0){
printf("T");
t--;
}
}
}



7-3 出租(20 分)

下面是新浪微博上曾经很火的一张图:

一时间网上一片求救声,急问这个怎么破。其实这段代码很简单,index数组就是arr数组的下标,index[0]=2 对应 arr[2]=1index[1]=0 对应 arr[0]=8index[2]=3 对应 arr[3]=0,以此类推…… 很容易得到电话号码是18013820100

本题要求你编写一个程序,为任何一个电话号码生成这段代码 —— 事实上,只要生成最前面两行就可以了,后面内容是不变的。

输入格式:

输入在一行中给出一个由11位数字组成的手机号码。

输出格式:

为输入的号码生成代码的前两行,其中arr中的数字必须按递减顺序给出。

输入样例:

18013820100

输出样例:

int[] arr = new int[]{8,3,2,1,0};
int[] index = new int[]{3,0,4,3,1,0,2,4,3,4,4};
#include
#include
#include
#include
#include
#include
using namespace std;
int shu[10];
int arr[10];
int main()
{
    char a[11];
    gets(a);
    int b[11];
    int i,j;
    for(i=0;i<11;i++)
    b[i]=a[i]-'0';
    memset(shu,0,sizeof(shu));
    for(i=0;i<11;i++)
    shu[b[i]]++;
    int flag=0;
    printf("int[] arr = new int[]{");
    for(i=9;i>=0;i--)
    {
        if(shu[i]!=0)
        {
            arr[flag]=i;
            flag++;
            if(flag==1)cout<             else cout<<","<         }
    }
    cout<<"};"<     printf("int[] index = new int[]{");
    int flag2=0;
    for(i=0;i<11;i++)
    {
        for(j=0;j         if(b[i]==arr[j])
        {
            flag2++;
            if(flag2==1)cout<             else cout<<","<             break;
        }
    }
    cout<<"};"<     return 0;
}

7-8 Left-pad(20 分)

根据新浪微博上的消息,有一位开发者不满NPM(Node Package Manager)的做法,收回了自己的开源代码,其中包括一个叫left-pad的模块,就是这个模块把javascript里面的React/Babel干瘫痪了。这是个什么样的模块?就是在字符串前填充一些东西到一定的长度。例如用*去填充字符串GPLT,使之长度为10,调用left-pad的结果就应该是******GPLT。Node社区曾经对left-pad紧急发布了一个替代,被严重吐槽。下面就请你来实现一下这个模块。

输入格式:

输入在第一行给出一个正整数N104)和一个字符,分别是填充结果字符串的长度和用于填充的字符,中间以1个空格分开。第二行给出原始的非空字符串,以回车结束。

输出格式:

在一行中输出结果字符串。

输入样例1:

15 _
I love GPLT

输出样例1:

____I love GPLT

输入样例2:

4 *
this is a sample for cut

输出样例2:

 cut
本题代码未经提交,不能确保正确性,样例都过。
#include
#include
#include
using namespace std;
char str[100000];
int main(){
int N,num;
char zf;
cin>>N;
getchar();
cin>>zf;
getchar();
gets(str);
int len = strlen(str);
if(N>len){
num = N- len;
for(int i=0;i cout< }
cout< }
else{
num = len-N;
for(int i=num;i cout< }
}
}



7-10 排座位(25 分)

布置宴席最微妙的事情,就是给前来参宴的各位宾客安排座位。无论如何,总不能把两个死对头排到同一张宴会桌旁!这个艰巨任务现在就交给你,对任何一对客人,请编写程序告诉主人他们是否能被安排同席。

输入格式:

输入第一行给出3个正整数:N100),即前来参宴的宾客总人数,则这些人从1到N编号;M为已知两两宾客之间的关系数;K为查询的条数。随后M行,每行给出一对宾客之间的关系,格式为:宾客1 宾客2 关系,其中关系为1表示是朋友,-1表示是死对头。注意两个人不可能既是朋友又是敌人。最后K行,每行给出一对需要查询的宾客编号。

这里假设朋友的朋友也是朋友。但敌人的敌人并不一定就是朋友,朋友的敌人也不一定是敌人。只有单纯直接的敌对关系才是绝对不能同席的。

输出格式:

对每个查询输出一行结果:如果两位宾客之间是朋友,且没有敌对关系,则输出No problem;如果他们之间并不是朋友,但也不敌对,则输出OK;如果他们之间有敌对,然而也有共同的朋友,则输出OK but...;如果他们之间只有敌对关系,则输出No way

输入样例:

7 8 4
5 6 1
2 7 -1
1 3 1
3 4 1
6 7 -1
1 2 1
1 4 1
2 3 -1
3 4
5 7
2 3
7 2

输出样例:

No problem
OK
OK but...
No way
敌人只能是a和b互为敌人,所以可以建二维数组存
朋友可以用最短路floy算,road[a][b]<1e9说明是朋友

#include
#include
using namespace std;
int road[101][101],didui[101][101];  // road数组存两人互为朋友 didui数组存两人互为敌人
int main(){
    int n,m,k,a,b,g;
    scanf("%d%d%d",&n,&m,&k);
    
    for(int i=1;i<101;i++){
        for(int j=1;j<101;j++){
            if(i==j)road[i][j]=0; //floy最短距离便知相同点距离为0 先设不相同两点距离1e9
            else road[i][j]=1e9;
        }
    }
    
    for(int i=0;i         scanf("%d%d%d",&a,&b,&g); //输入两人及其关系
        if(g==1){
            road[a][b]=1;
            road[b][a]=1;
        }
        if(g==-1){
            didui[a][b]=-1;
            didui[b][a]=-1;
        }
    }
    
    for(int k=1;k<=n;k++){//floyd求所有朋友 //floyd的经典之处 三层循环
        for(int i=1;i<=n;i++){
            for(int j=1;j<=n;j++){

                road[i][j]=min(road[i][j],road[i][k]+road[k][j]);
            }
        }
    }
    
    for(int i=0;i         scanf("%d%d",&a,&b);
        if(road[a][b]<1e9){
            if(didui[a][b]==-1)printf("OK but...\n");
            else printf("No problem\n");
        }
        else{
            if(didui[a][b]==-1)printf("No way\n");
            else printf("OK\n");
        }
    }
    return 0;
}



7-9 红色警报(25 分)

战争中保持各个城市间的连通性非常重要。本题要求你编写一个报警程序,当失去一个城市导致国家被分裂为多个无法连通的区域时,就发出红色警报。注意:若该国本来就不完全连通,是分裂的k个区域,而失去一个城市并不改变其他城市之间的连通性,则不要发出警报。

输入格式:

输入在第一行给出两个整数N(0 < N  500)和M 5000),分别为城市个数(于是默认城市从0到N-1编号)和连接两城市的通路条数。随后M行,每行给出一条通路所连接的两个城市的编号,其间以1个空格分隔。在城市信息之后给出被攻占的信息,即一个正整数K和随后的K个被攻占的城市的编号。

注意:输入保证给出的被攻占的城市编号都是合法的且无重复,但并不保证给出的通路没有重复。

输出格式:

对每个被攻占的城市,如果它会改变整个国家的连通性,则输出Red Alert: City k is lost!,其中k是该城市的编号;否则只输出City k is lost.即可。如果该国失去了最后一个城市,则增加一行输出Game Over.

输入样例:

5 4
0 1
1 3
3 0
0 4
5
1 2 0 4 3

输出样例:

City 1 is lost.
City 2 is lost.
Red Alert: City 0 is lost!
City 4 is lost.
City 3 is lost.
Game Over.
错误代码:无向图,连通就是1,不连通就是0,当所有都是0的时刻,就是红色警报的时刻。代码的错误在于红色警报城市之后的城市也处于红色警报,可能还有其他错误,暂时无法识别。
#include
#include
#include
using namespace std;
int main(){
int n,m,k;
int a,b;
int lost;
cin>>n>>m;
int place[n][n];
memset(place,0,sizeof(place));
while(m--){
cin>>a>>b;
place[a][b]=1;
place[b][a]=1;
}
if(m==0){
cin>>k;
printf("City %d is lost\n",k);
n--;
if(n==0)
printf("Game Over.\n");
}
else{
cin>>k;
while(k--){
int flag=0;
cin>>lost;
for(int i=0;i if(place[lost][i]==1||place[i][lost]==1){
place[lost][i]=0;
place[i][lost]=0;
}
}
for(int i=0;i for(int j=0;j if(place[i][j]==1){
flag=1;
break;
}
}
if(flag==1)
break;
}
if(flag==0){
printf("Red Alert:City %d is lost!\n",lost);
}else
printf("City %d is lost.\n",lost);
n--;
if(n==0)
printf("Game Over.\n");
}
}
}
正确代码: 并查集
#include
using namespace std;
int a[505], n;
struct node
{
    int x;
    int y;
};
int fi(int x)//查找根
{
    while(x != a[x])
    {
        x = a[x];
    }
    return x;
}
void uni(int x, int y)//并
{
    int x1 = fi(x);
    int y1 = fi(y);
    if(x1 != y1)
    {
        a[y1] = x1;
    }
}
void pp()//初始化
{
    int i;
    for(i = 0; i < n; i++)
    {
        a[i] = i;
    }
}
int main()
{
    int m, i, u, v;
    node eg[5005];//记录那两个城市连接
    int vis[505], cnt, sum;
    while(~scanf("%d %d", &n, &m))
    {
        pp();//初始化数组a
        for(i = 0; i < m; i++)
        {
            scanf("%d %d", &u, &v);
            eg[i].x = u;
            eg[i].y = v;
            uni(u, v);//将连通的城市并起来
        }
        sum = 0;//记录城市分为几块
        for(i = 0; i < n; i++)
        {
            if(i == a[i]) sum++;//记录城市分为几块
        }
        int k, num;
        scanf("%d", &k);
        memset(vis, 0, sizeof(vis));//标记城市,被攻占
        for(int j = 0; j < k; j++)
        {
            pp();//初始化数组a
            scanf("%d", &num);//输入被攻占的城市
            vis[num] = 1;//标记城市被攻占
            for(i = 0; i < m; i++)
            {
                if(vis[eg[i].x] == 1 || vis[eg[i].y] == 1) continue;//如果跟被攻占有关的城市不需要并
                uni(eg[i].x, eg[i].y);//否则并起来
            }
            cnt = 0;
            for(i = 0; i < n; i++)
            {
                if(a[i] == i) cnt++;//看看现在城市分为几块
            }
            if(cnt - 1 == sum || cnt == sum)//满足条件代表,城市还连通
            printf("City %d is lost.\n", num);
            else printf("Red Alert: City %d is lost!\n", num);//否则城市不连通
            sum = cnt;//更新现在城市分为几块的值
        }
        if(k >= n) printf("Game Over.\n");
    }
}


7-11 互评成绩(25 分)

学生互评作业的简单规则是这样定的:每个人的作业会被k个同学评审,得到k个成绩。系统需要去掉一个最高分和一个最低分,将剩下的分数取平均,就得到这个学生的最后成绩。本题就要求你编写这个互评系统的算分模块。

输入格式:

输入第一行给出3个正整数N(3 < N 104,学生总数)、k(3  k  10,每份作业的评审数)、M 20,需要输出的学生数)。随后N行,每行给出一份作业得到的k个评审成绩(在区间[0, 100]内),其间以空格分隔。

输出格式:

按非递减顺序输出最后得分最高的M个成绩,保留小数点后3位。分数间有1个空格,行首尾不得有多余空格。

输入样例:

6 5 3
88 90 85 99 60
67 60 80 76 70
90 93 96 99 99
78 65 77 70 72
88 88 88 88 88
55 55 55 55 55

输出样例:

87.667 88.000 96.000
在5个成绩中去掉一个最高分和一个最低分,除3求平均值。
#include
#include
#include
#include
using namespace std;
int main()
{
    int n, k, m;
    double ans[10100], c, cj[11];;
    scanf("%d%d%d", &n, &k, &m);
    for(int i = 0; i < n; i++)
    {
        for(int j = 0; j < k; j++)
        scanf("%lf", &cj[j]);
        sort(cj, cj + k);
        ans[i] = 0;
        for(int j = 1; j < k - 1; j++)
        ans[i] += cj[j];
        ans[i] /= (k-2);
    }
    sort(ans, ans + n);
    printf("%.3lf", ans[n-m]);
    for(int i = n-m+1; i < n; i++)
    printf(" %.3lf", ans[i]);
    printf("\n");
    return 0;
}


7-9 红色警报(25 分)

战争中保持各个城市间的连通性非常重要。本题要求你编写一个报警程序,当失去一个城市导致国家被分裂为多个无法连通的区域时,就发出红色警报。注意:若该国本来就不完全连通,是分裂的k个区域,而失去一个城市并不改变其他城市之间的连通性,则不要发出警报。

输入格式:

输入在第一行给出两个整数N(0 < N  500)和M 5000),分别为城市个数(于是默认城市从0到N-1编号)和连接两城市的通路条数。随后M行,每行给出一条通路所连接的两个城市的编号,其间以1个空格分隔。在城市信息之后给出被攻占的信息,即一个正整数K和随后的K个被攻占的城市的编号。

注意:输入保证给出的被攻占的城市编号都是合法的且无重复,但并不保证给出的通路没有重复。

输出格式:

对每个被攻占的城市,如果它会改变整个国家的连通性,则输出Red Alert: City k is lost!,其中k是该城市的编号;否则只输出City k is lost.即可。如果该国失去了最后一个城市,则增加一行输出Game Over.

输入样例:

5 4
0 1
1 3
3 0
0 4
5
1 2 0 4 3

输出样例:

City 1 is lost.
City 2 is lost.
Red Alert: City 0 is lost!
City 4 is lost.
City 3 is lost.
Game Over.

7-10 列车调度(25 分)

火车站的列车调度铁轨的结构如下图所示。

两端分别是一条入口(Entrance)轨道和一条出口(Exit)轨道,它们之间有N条平行的轨道。每趟列车从入口可以选择任意一条轨道进入,最后从出口离开。在图中有9趟列车,在入口处按照{8,4,2,5,3,9,1,6,7}的顺序排队等待进入。如果要求它们必须按序号递减的顺序从出口离开,则至少需要多少条平行铁轨用于调度?

输入格式:

输入第一行给出一个整数N (2  N 105),下一行给出从1到N的整数序号的一个重排列。数字间以空格分隔。

输出格式:

在一行中输出可以将输入的列车按序号递减的顺序调离所需要的最少的铁轨条数。

输入样例:

9
8 4 2 5 3 9 1 6 7

输出样例:

4


7-12 愿天下有情人都是失散多年的兄妹(25 分)

呵呵。大家都知道五服以内不得通婚,即两个人最近的共同祖先如果在五代以内(即本人、父母、祖父母、曾祖父母、高祖父母)则不可通婚。本题就请你帮助一对有情人判断一下,他们究竟是否可以成婚?

输入格式:

输入第一行给出一个正整数N(2  N 104),随后N行,每行按以下格式给出一个人的信息:

本人ID 性别 父亲ID 母亲ID

其中ID是5位数字,每人不同;性别M代表男性、F代表女性。如果某人的父亲或母亲已经不可考,则相应的ID位置上标记为-1

接下来给出一个正整数K,随后K行,每行给出一对有情人的ID,其间以空格分隔。

注意:题目保证两个人是同辈,每人只有一个性别,并且血缘关系网中没有乱伦或隔辈成婚的情况。

输出格式:

对每一对有情人,判断他们的关系是否可以通婚:如果两人是同性,输出Never Mind;如果是异性并且关系出了五服,输出Yes;如果异性关系未出五服,输出No

输入样例:

24
00001 M 01111 -1
00002 F 02222 03333
00003 M 02222 03333
00004 F 04444 03333
00005 M 04444 05555
00006 F 04444 05555
00007 F 06666 07777
00008 M 06666 07777
00009 M 00001 00002
00010 M 00003 00006
00011 F 00005 00007
00012 F 00008 08888
00013 F 00009 00011
00014 M 00010 09999
00015 M 00010 09999
00016 M 10000 00012
00017 F -1 00012
00018 F 11000 00013
00019 F 11100 00018
00020 F 00015 11110
00021 M 11100 00020
00022 M 00016 -1
00023 M 10012 00017
00024 M 00022 10013
9
00021 00024
00019 00024
00011 00012
00022 00018
00001 00004
00013 00016
00017 00015
00019 00021
00010 00011

输出样例:

Never Mind
Yes
Never Mind
No
Yes
No
Yes
No
No


7-9 抢红包(25 分)

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

输入格式:

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

KN1P1NKPK

其中K0K20)是发出去的红包个数,Ni是抢到红包的人的编号,Pi>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排序,之后输出,take初值一开始没想到怎么赋值,然后sort也出现问题,就百度了。结合百度,又更改了自己的代码。
#include
#include
#include
using namespace std;
struct node{ //题目就能知道每个id都有抢的钱,都有id,都有发包数量,就选择了结构体。
double take;
int id;
int count;
}people[100100];
int cmd(struct node a,struct node b) //排序比较的基本情况
{
    if(a.take != b.take)
        return a.take > b.take;  //金额递减
    else if(a.count != b.count)
        return a.count > b.count ; //红包个数递减
    else if(a.id != b.id)
        return a.id < b.id ; //个人编号递增
}
int main(){
int n;
int k;
cin>>n;
for(int i=0;i<=n;i++){ //一开始没想到怎么给结构体赋初值,百度之后也没找到准确答案,看到此代码才知道有这种bug...
people[i].take=0;
people[i].count=0;
people[i].id=i;
}
for(int i=1;i<=n;i++){
cin>>k;
double sum=0;
for(int j=1;j<=k;j++){
int id;
double money=0;
scanf("%d%lf",&id,&money);
people[id].take+=money/100.0; //对应着id,金额从0加,得到抢到红包金额数。
people[id].count++;
sum+=money;
}
people[i].take-=sum/100.0;//减去i人发的红包
}
sort(people+1,people+n+1,cmd);
for(int i=1;i<=n;i++){
printf("%d %.2lf\n",people[i].id,people[i].take);
}
}

7-13 是否完全二叉搜索树(30 分)

将一系列给定数字顺序插入一个初始为空的二叉搜索树(定义为左子树键值大,右子树键值小),你需要判断最后的树是否一棵完全二叉树,并且给出其层序遍历的结果。

输入格式:

输入第一行给出一个不超过20的正整数N;第二行给出N个互不相同的正整数,其间以空格分隔。

输出格式:

将输入的N个正整数顺序插入一个初始为空的二叉搜索树。在第一行中输出结果树的层序遍历结果,数字间以1个空格分隔,行的首尾不得有多余空格。第二行输出YES,如果该树是完全二叉树;否则输出NO

输入样例1:

9
38 45 42 24 58 30 67 12 51

输出样例1:

38 45 24 58 42 30 12 67 51
YES

输入样例2:

8
38 24 12 45 58 67 42 51

输出样例2:

38 45 24 58 42 12 67 51
NO


7-13 是否完全二叉搜索树(30 分)

将一系列给定数字顺序插入一个初始为空的二叉搜索树(定义为左子树键值大,右子树键值小),你需要判断最后的树是否一棵完全二叉树,并且给出其层序遍历的结果。

输入格式:

输入第一行给出一个不超过20的正整数N;第二行给出N个互不相同的正整数,其间以空格分隔。

输出格式:

将输入的N个正整数顺序插入一个初始为空的二叉搜索树。在第一行中输出结果树的层序遍历结果,数字间以1个空格分隔,行的首尾不得有多余空格。第二行输出YES,如果该树是完全二叉树;否则输出NO

输入样例1:

9
38 45 42 24 58 30 67 12 51

输出样例1:

38 45 24 58 42 30 12 67 51
YES

输入样例2:

8
38 24 12 45 58 67 42 51

输出样例2:

38 45 24 58 42 12 67 51
NO

#include
#include
#include
int a[100],b;
int n;
void add(int i,int d){   //递归插入 该行的左子树是上一行父节点的2倍,右子树是2倍+1,如果此时这棵树的接点不满,就把这个d当作这个接点。
if(a[i]==-1){
a[i]=d;
return;
}
if(d>a[i])
add(i*2,d);
else
add(i*2+1,d);
}
int main(){
scanf("%d",&n);
memset(a,-1,sizeof(a));
for(int i=0;i scanf("%d",&b);
add(1,b);
}
int c=0,i=0;
while(c while(a[i]==-1)
i++;
if(c)
printf(" %d",a[i]);
else
printf("%d",a[i]);
i++;
c++;
}
if(i==n+1)
printf("\nYES");
else
printf("\nNO");
}

7-14 直捣黄龙(30 分)

本题是一部战争大片 —— 你需要从己方大本营出发,一路攻城略地杀到敌方大本营。首先时间就是生命,所以你必须选择合适的路径,以最快的速度占领敌方大本营。当这样的路径不唯一时,要求选择可以沿途解放最多城镇的路径。若这样的路径也不唯一,则选择可以有效杀伤最多敌军的路径。

输入格式:

输入第一行给出2个正整数N(2  N  200,城镇总数)和K(城镇间道路条数),以及己方大本营和敌方大本营的代号。随后N-1行,每行给出除了己方大本营外的一个城镇的代号和驻守的敌军数量,其间以空格分隔。再后面有K行,每行按格式城镇1 城镇2 距离给出两个城镇之间道路的长度。这里设每个城镇(包括双方大本营)的代号是由3个大写英文字母组成的字符串。

输出格式:

按照题目要求找到最合适的进攻路径(题目保证速度最快、解放最多、杀伤最强的路径是唯一的),并在第一行按照格式己方大本营->城镇1->...->敌方大本营输出。第二行顺序输出最快进攻路径的条数、最短进攻距离、歼敌总数,其间以1个空格分隔,行首尾不得有多余空格。

输入样例:

10 12 PAT DBY
DBY 100
PTA 20
PDS 90
PMS 40
TAP 50
ATP 200
LNN 80
LAO 30
LON 70
PAT PTA 10
PAT PMS 10
PAT ATP 20
PAT LNN 10
LNN LAO 10
LAO LON 10
LON DBY 10
PMS TAP 10
TAP DBY 10
DBY PDS 10
PDS PTA 10
DBY ATP 10

输出样例:

PAT->PTA->PDS->DBY
3 30 210


7-15 水果忍者(30 分)

2010年风靡全球的“水果忍者”游戏,想必大家肯定都玩过吧?(没玩过也没关系啦~)在游戏当中,画面里会随机地弹射出一系列的水果与炸弹,玩家尽可能砍掉所有的水果而避免砍中炸弹,就可以完成游戏规定的任务。如果玩家可以一刀砍下画面当中一连串的水果,则会有额外的奖励,如图1所示。

图 1

现在假如你是“水果忍者”游戏的玩家,你要做的一件事情就是,将画面当中的水果一刀砍下。这个问题看上去有些复杂,让我们把问题简化一些。我们将游戏世界想象成一个二维的平面。游戏当中的每个水果被简化成一条一条的垂直于水平线的竖直线段。而一刀砍下我们也仅考虑成能否找到一条直线,使之可以穿过所有代表水果的线段。

图 2

如图2所示,其中绿色的垂直线段表示的就是一个一个的水果;灰色的虚线即表示穿过所有线段的某一条直线。可以从上图当中看出,对于这样一组线段的排列,我们是可以找到一刀切开所有水果的方案的。

另外,我们约定,如果某条直线恰好穿过了线段的端点也表示它砍中了这个线段所表示的水果。假如你是这样一个功能的开发者,你要如何来找到一条穿过它们的直线呢?

输入格式:

输入在第一行给出一个正整数N104),表示水果的个数。随后N行,每行给出三个整数xy1y2,其间以空格分隔,表示一条端点为(x,y1)(x,y2)的水果,其中y1>y2。注意:给出的水果输入集合一定存在一条可以将其全部穿过的直线,不需考虑不存在的情况。坐标为区间 [106,106) 内的整数。

输出格式:

在一行中输出穿过所有线段的直线上具有整数坐标的任意两点p1(x1,y1)p2(x2,y2),格式为 x1y1x2y2。注意:本题答案不唯一,由特殊裁判程序判定,但一定存在四个坐标全是整数的解。

输入样例:

5
-30 -52 -84
38 22 -49
-99 -22 -99
48 59 -18
-36 -50 -72

输出样例:

-99 -99 -30 -52

你可能感兴趣的:(PAT)