2020.10.10--pta阶梯赛练习2补题

7-3.N个数求和

本题的要求很简单,就是求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
题解:用gcd()函数求出最大公约数进而化简分数;
要注意不要出现除以0 的情况,不然就会浮点错误
#include<bits/stdc++.h>
using namespace std;
long long gcd(long long a,long long b)
{
    long long t;
    if(a==0)return 0;
    else {
        while(b)
        {
        t=a%b;
        a=b;
        b=t;
        }
        return a;
    }

}
int main()
{
   long long n,x=0,y=1,a[110],b[110],h;
   char ch;
   scanf("%lld",&n);
   scanf("%lld/%lld",&a[0],&b[0]);
   h=gcd(a[0],b[0]);
   x=a[0];
   y=b[0];
   if(x!=0)//**
   {
       x=x/h;
       y=y/h;
   }
   long long k,q;

   for(long long i=1;i<n;i++)
   {
       scanf("%lld/%lld",&a[i],&b[i]);
       k=y/gcd(y,b[i])*b[i];//求合并后的分母
       x=x*k/y+a[i]*k/b[i];//求合并后的分子
       y=k;
       h=gcd(x,y);
       if(h)//避免浮点错误
       {
           x/=h;
           y/=h;
       }
   }
   //分情况讨论
   if(x!=0&&x/y==0)
   {
       printf("%lld/%lld\n",x%y,y);
   }
   else if(x%y==0)
   {
       printf("%lld\n",x/y);
   }
   else
   {
       printf("%lld %lld/%lld\n",x/y,x%y,y);
   }

}

7-9 名人堂与代金券

对于在中国大学MOOC(http://www.icourse163.org/ )学习“数据结构”课程的学生,想要获得一张合格证书,总评成绩必须达到 60 分及以上,并且有另加福利:总评分在 [G, 100] 区间内者,可以得到 50 元 PAT 代金券;在 [60, G) 区间内者,可以得到 20 元PAT代金券。全国考点通用,一年有效。同时任课老师还会把总评成绩前 K 名的学生列入课程“名人堂”。本题就请你编写程序,帮助老师列出名人堂的学生,并统计一共发出了面值多少元的 PAT 代金券。

输入格式:

输入在第一行给出 3 个整数,分别是 N(不超过 10 000 的正整数,为学生总数)、G(在 (60,100) 区间内的整数,为题面中描述的代金券等级分界线)、K(不超过 100 且不超过 N 的正整数,为进入名人堂的最低名次)。接下来 N 行,每行给出一位学生的账号(长度不超过15位、不带空格的字符串)和总评成绩(区间 [0, 100] 内的整数),其间以空格分隔。题目保证没有重复的账号。

输出格式:

首先在一行中输出发出的 PAT 代金券的总面值。然后按总评成绩非升序输出进入名人堂的学生的名次、账号和成绩,其间以 1 个空格分隔。需要注意的是:成绩相同的学生享有并列的排名,排名并列时,按账号的字母序升序输出。

输入样例:

10 80 5
cy@zju.edu.cn 78
cy@pat-edu.com 87
1001@qq.com 65
uh-oh@163.com 96
test@126.com 39
anyone@qq.com 87
zoe@mit.edu 80
jack@ucla.edu 88
bob@cmu.edu 80
ken@163.com 70
 

输出样例:

360
1 uh-oh@163.com 96
2 jack@ucla.edu 88
3 anyone@qq.com 87
3 cy@pat-edu.com 87
5 bob@cmu.edu 80
5 zoe@mit.edu 80
题解:根据题意进行排序,但要注意序号的输出,用结构体输入每人的账号和成绩,再用判断函数进行从大到小和从小到大的排序,节约时间
#include<bits/stdc++.h>
using namespace std;
struct Student
{
    string s;
    int score;
}str[10010];
bool cmp(Student a,Student b)
{
    if(a.score==b.score)return a.s<b.s;
    else return a.score>b.score;
}
int main()
{
   int n,g,k,i,j;
  // string s[10010];
   int ct=0;
   cin>>n>>g>>k;
   for(i=0;i<n;i++)
   {
       cin>>str[i].s;
       getchar();
       cin>>str[i].score;
       if(str[i].score>=g&&str[i].score<=100)ct+=50;
       else if(str[i].score>=60&&str[i].score<g)ct+=20;
   }
   int m=0;
   sort(str,str+n,cmp);
   /*for(i=0;i<n;i++)
   {
       for(j=i+1;j<n;j++)
       {
           if(str[i].score<str[j].score)
           {
               t[i]=str[i];
               str[i]=str[j];
               str[j]=t[i];
           }
           else if(str[i].score==str[j].score)
           {
               if(str[i].s>str[j].s)
               {
                   t[i]=str[i];
                  str[i]=str[j];
                  str[j]=t[i];
               }
           }
       }
   }*/
   cout<<ct<<endl;
   int r=0,q=0;
   for(i=0;i<n;i++)
   {
       if(q!=str[i].score&&i>=k)break;
       if(q!=str[i].score)
       {
           r=i+1;
       }
       cout<<r<<" "<<str[i].s<<" "<<str[i].score<<endl;
       q=str[i].score;

   }

}

 7-11 部落

在一个社区里,每个人都有自己的小圈子,还可能同时属于很多不同的朋友圈。我们认为朋友的朋友都算在一个部落里,于是要请你统计一下,在一个给定社区中,到底有多少个互不相交的部落?并且检查任意两个人是否属于同一个部落。

输入格式:

输入在第一行给出一个正整数N(≤),是已知小圈子的个数。随后N行,每行按下列格式给出一个小圈子里的人:

⋯ [

其中K是小圈子里的人数,[(,)是小圈子里每个人的编号。这里所有人的编号从1开始连续编号,最大编号不会超过1。

之后一行给出一个非负整数Q(≤),是查询次数。随后Q行,每行给出一对被查询的人的编号。

输出格式:

首先在一行中输出这个社区的总人数、以及互不相交的部落的个数。随后对每一次查询,如果他们属于同一个部落,则在一行中输出Y,否则输出N

输入样例:

4
3 10 1 2
2 3 4
4 1 5 7 8
3 9 6 4
2
10 5
3 7
 

输出样例:

10 2
Y
N

题解:(运用并查集)
用一个数组(例fa[])来存储每个元素的父节点,现将他们的父节点设为他们自身,然后将同一个圈子的元素的父节点设为其中的同一个元素,就是该圈子元素的父节点相同
然后再查询两个元素的父节点是否一样,一样则输出“Y”,否则输出“N”;另设一个数组,初始化为0,将下标为编号的赋值为1,用于计算社区总人数,然后再遍历总人数,利用父节点等于自身下标来计算部落个数
#include<bits/stdc++.h>
using namespace std;
int fa[10100],rank[10100]={0};
//memset(rank,0,sizeof rank);
/*inline void init(int k,int n)
{
    fa[n]=k;
    rank[k]++;
}*/
int find (int x)//查找父节点
{
    return x==fa[x]?x:(fa[x]=find(fa[x]));
}
inline void  marge(int i,int j)//合并为相同的父节点
{
     int x=find(i),y=find(j);
     if(x!=y)
     {
         fa[x]=y;
     }
    // else fa[y]=x;
     //if(rank[x]==rank[y]&&x!=y)rank[y]++;
}
int main()
{
    int n;
    cin>>n;
    int ct=0;
    for(int i=0;i<10001;i++)fa[i]=i;//初始化,将每个数的父结点初始化为自身
    int k,b[10100]={0};
    while(n--)
    {

        cin>>k;
        int s[k+5];
        cin>>s[0];
        b[s[0]]=1;
        for(int i=1;i<k;i++)
        {
            cin>>s[i];
           // init(k,s[i]);
            b[s[i]]=1;//记录数组,用于计算社区总人数
            marge(s[i],s[i-1]);
        }
    }
    for(int i=0;i<10001;i++)
    {
        if(b[i]==1)ct++;
    }
    cout<<ct<<" ";
    int j=0;
    for(int i=1;i<=ct;i++)
    {
        if(fa[i]==i)j++;//如果下标和数不一样则是不同的部落
    }
    cout<<j<<endl;
    int q;
    cin>>q;
    while(q--)
    {
        int x,y;
        cin>>x>>y;
       // marge(x,y);
        printf("%s\n",find(x)==find(y)?"Y":"N");
    }
}

 7-10.链表去重

给定一个带整数键值的链表 L,你需要把其中绝对值重复的键值结点删掉。即对每个键值 K,只有第一个绝对值等于 K 的结点被保留。同时,所有被删除的结点须被保存在另一个链表上。例如给定 L 为 21→-15→-15→-7→15,你需要输出去重后的链表 21→-15→-7,还有被删除的链表 -15→15。

输入格式:

输入在第一行给出 L 的第一个结点的地址和一个正整数 N(≤,为结点总数)。一个结点的地址是非负的 5 位整数,空地址 NULL 用 -1 来表示。

随后 N 行,每行按以下格式描述一个结点:

地址 键值 下一个结点
 

其中地址是该结点的地址,键值是绝对值不超过1的整数,下一个结点是下个结点的地址。

输出格式:

首先输出去重后的链表,然后输出被删除的链表。每个结点占一行,按输入的格式输出。

输入样例:

00100 5
99999 -7 87654
23854 -15 00000
87654 15 -1
00000 -15 99999
00100 21 23854
 

输出样例:

00100 21 23854
23854 -15 99999
99999 -7 -1
00000 -15 87654
87654 15 -1

 题解:与天梯赛练习一里7-11重排链表一个做法,将链表重排,再用一个数组将排好的地址依次存储下来,再根据键值的绝对值将链表分为两部分

#include<bits/stdc++.h>
#include<vector>
using namespace std;
const int N=100000;
struct Node
{
    int ad;//地址
    int data;//键值
    int next;//下个节点地址
}s[N];
int main()
{
    vector<Node>b;
    int i,f,n,j=0,x,y,z;
    cin>>f>>n;
    for(i=0;i<n;i++)
    {
        cin>>x>>y>>z;
        s[x].ad=x;
        s[x].data=y;
        s[x].next=z;
    }
    int w[N]={0},q[N]={0},t[N]={0};
    int c[N]={0},cnt=0;
    while(f!=-1)
    {
        c[cnt++]=f;//存储地址
        b.push_back(s[f]);//链表按地址依次排序存储到b中
        f=s[f].next;
    }
    int m=b.size();
    cout<<m<<endl;
    int k=0,p=0;
    for(i=0;i<m;i++)
    {
        if(w[abs(b[i].data)]==0)
        {
            w[abs(b[i].data)]=1;//标记绝对值重复的键值
            q[k++]=c[i];

           // cout<<" q[k]="<<q[k-1]<<" b[i].ad="<<b[i].data<<endl;
        }
        else
        {
            t[p++]=c[i];
           // cout<<" t[p]="<<t[p-1]<<" b[i].ad="<<b[i].data<<endl;
        }
    }
     for(i=0;i<k;i++)
     {
         //cout<<b[i].data<<endl;
        cout << setw(5) << setfill('0') << q[i] << " " << s[q[i]].data<<" ";
        if(i!=k-1) cout << setw(5) << setfill('0') << q[i+1]<<endl;
        else cout << -1 <<endl;
     }
     //cout<<p<<" "<<t[1]<<" "<<s[t[1]].data<<endl;
     for(int j=0; j<p; j++){
            //cout<<b[87654].data<<endl;
        cout << setw(5) << setfill('0') << t[j] << " " << s[t[j]].data<<" ";
        if(j!=p-1) cout << setw(5) << setfill('0') << t[j+1]<<endl;
        else cout << -1 <<endl;
    }
}

 7-1估值一亿的AI核心代码

 

 

以上图片来自新浪微博。

本题要求你实现一个稍微更值钱一点的 AI 英文问答程序,规则是:

  • 无论用户说什么,首先把对方说的话在一行中原样打印出来;
  • 消除原文中多余空格:把相邻单词间的多个空格换成 1 个空格,把行首尾的空格全部删掉,把标点符号前面的空格删掉;
  • 把原文中所有大写英文字母变成小写,除了 I
  • 把原文中所有独立的 can youcould you 对应地换成 I canI could—— 这里“独立”是指被空格或标点符号分隔开的单词;
  • 把原文中所有独立的 I 和 me 换成 you
  • 把原文中所有的问号 ? 换成惊叹号 !
  • 在一行中输出替换后的句子作为 AI 的回答。

输入格式:

输入首先在第一行给出不超过 10 的正整数 N,随后 N 行,每行给出一句不超过 1000 个字符的、以回车结尾的用户的对话,对话为非空字符串,仅包括字母、数字、空格、可见的半角标点符号。

输出格式:

按题面要求输出,每个 AI 的回答前要加上 AI: 和一个空格。

输入样例:

6
Hello ?
 Good to chat   with you
can   you speak Chinese?
Really?
Could you show me 5
What Is this prime? I,don 't know
 

输出样例:

Hello ?
AI: hello!
 Good to chat   with you
AI: good to chat with you
can   you speak Chinese?
AI: I can speak chinese!
Really?
AI: really!
Could you show me 5
AI: I could show you 5
What Is this prime? I,don 't know
AI: what Is this prime! you,don't know
 

 

#include<string>
#include<iostream>
#include<vector>
#include<cstdio>
using namespace std;
int main()
{
    int n,i;
    cin>>n;
    getchar();
    string s;
    vector<string>b;//每个元素都是字符串类型数组;
    while(n--)
    {

        //cout<<n<<endl;
        getline(cin,s);
        cout<<s<<endl<<"AI: ";
        //cout<<"AI: ";
       
        //cout<<m<<endl;
        for(i=0;i<s.size();i++)
        {
            if(s[i]>='A'&&s[i]<='Z')
            {
                if(s[i]!='I')s[i]+=32;
            }
            else if((s[i]>='0'&&s[i]<='9')||(s[i]>='a'&&s[i]<='z'))continue;
            else if(s[i]!=' ')//排除字母和数字后当为标点符号时
            {
                s.insert(i," ");//在标点符号前插入空格,便于找出独立性的单词
                i++;
            }
            if(s[i]=='?')s[i]='!';
        }
        string temp="";
        //int q=0;
        for(i=0;i<s.size();i++)
        {
            if(s[i]!=' ')
            {
                temp+=s[i];
            }
            else
            {
                if(temp!=""){
                    b.push_back(temp);//将单词或者数字依次存储在b中;
                    temp="";
                }
                //cout<<b[q]<<"*"<<endl;
                //q++;
            }
        }
       // cout<<q<<endl;
        if(temp!="")b.push_back(temp);//存储第m-1个
        //int w=b.size();
        //cout<<w<<endl;
        for(int j=0;j<b.size();j++)
        {
            if(b[j]=="I"||b[j]=="me")b[j]="you";
            else if(b[j]=="can"||b[j]=="could")
            {
                if((j+1)<b.size())
                {
                    if(b[j+1]=="you")
                    {
                        b[j+1]=b[j];
                        b[j]="I";
                        //b[i+1]=
                    }
                }
            }
        }
        for(i=0;i<b.size();i++)
        {
            cout<<b[i];
            if(i==b.size()-1)break;
            if((b[i+1][0]>='0'&&b[i+1][0]<='9')||(b[i+1][0]>='a'&&b[i+1][0]<='z')||b[i+1][0]=='I')
            {
               printf(" ");
            }
        }
       printf("\n");
        //cout<<n<<endl;
        b.clear();//清空数组b
    }
    return 0;
}

 

 
posted @ 2020-10-18 16:13  西瓜0  阅读(305)  评论(0)    收藏  举报