【PAT甲级真题整理四】1091~1120

目录

1092 To Buy or Not to Buy(20)模拟

1093 Count PAT's(25)思维

1094 The Largest Generation(25)dfs或bfs

1095 Cars on Campus (30)排序+思维

1096 Consecutive Factors(20)思维

1097 Deduplication on a Linked List(25)链表

1098 Insertion or Heap Sort (25)插入和堆排序

1099 Build A Binary Search Tree(30)二叉查找树

1100 Mars Numbers(20)字符串处理

1101 Quick Sort(25)快速排序

1102 Invert a Binary Tree(25)树的遍历

1103 Integer Factorization(30)dfs+剪枝

1104 Sum of Number Segments(20)思维

1106 Lowest Price in Supply Chain(25)树的遍历

1107 Social Clusters(30)并查集

1108 Finding Average(20)字符串处理

1109 Group Photo(25)排序

1110 Complete Binary Tree(25)bfs判断完全二叉树

1112 Stucked Keyboard(20)字符串处理

1113 Integer Set Partition(25)水题

1114 Family Property(25)并查集+排序

1116 Come on! Let's C(20)模拟

1117 Eddington Number(25)水题

1118 Birds in Forest(25)并查集

1120 Friend Numbers(20)set的使用


1092 To Buy or Not to Buy(20)模拟

【题意】

Eva需要给定数目及颜色的珠子,若商店的珠子满足她的需求,则输出Yes,并输出她需要多买多少珠子,如果不能满足则输出No,并输出还差多少珠子可以满足她的需求。

【解题思路】

用s1存储Eva需要的不同颜色珠子的个数,s2存储商店有的不同颜色珠子的个数,然后比较就可以了。

【代码】

#include<bits/stdc++.h>
using namespace std;
const int maxn=1005;
char a[maxn],b[maxn];
int s1[205],s2[205];
int main()
{
    int flag=1,ans1=0,ans2=0;
    scanf("%s%s",a,b);
    for(int i=0;i<strlen(b);i++)
        s1[b[i]]++;
    for(int i=0;i<strlen(a);i++)
        s2[a[i]]++;
    for(int i=0;i<205;i++)
    {
        if(s1[i]>s2[i])
        {
            flag=0;
            ans2+=s1[i]-s2[i];
        }
        else ans1+=s2[i]-s1[i];
    }
    if(flag)printf("Yes %d\n",ans1);
    else printf("No %d\n",ans2);
    return 0;
}

 

1093 Count PAT's(25)思维

【题意】

给一个字符串输出最多能构成多少PAT。

【解题思路】

这是一道思维题……暴力的话只能拿15分。只要记录对于每一个A,前面有多少个P,后面有多少个T,他们的乘积即是这个A能组成的PAT的个数,然后所有相加即是最终答案。

【代码】

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
const int mod=1000000007;
char s[maxn];
int main()
{
    scanf("%s",s);
    int len=strlen(s);
    int ans=0,cntP=0,cntA=0,cntT=0;
    for(int i=0;i<len;i++)
        if(s[i]=='T')cntT++;
    for(int i=0;i<len;i++)
    {
        if(s[i]=='P')cntP++;
        else if(s[i]=='T')cntT--;
        else if(s[i]=='A')ans=(ans+cntP%mod*cntT%mod)%mod;
    }
    printf("%d\n",ans);
    return 0;
}

 

1094 The Largest Generation(25)dfs或bfs

【题意】

给一棵树,计算哪一层的结点数最多,并输出该结点数和所在层数。

【解题思路】

用dfs或bfs都可以,用book数组记录每一层的结点数。用bfs时,用level数组记录每个节点所在的层数。

【代码】

dfs:

#include<bits/stdc++.h>
using namespace std;
const int maxn=105;
vector<int>v[maxn];
int book[maxn];
void dfs(int x,int level)
{
    book[level]++;
    for(int i=0;i<v[x].size();i++)
        dfs(v[x][i],level+1);
}
int main()
{
    memset(book,0,sizeof(book));
    int n,m;
    scanf("%d%d",&n,&m);
    while(m--)
    {
        int x,num,t;
        scanf("%d%d",&x,&num);
        while(num--)
        {
            scanf("%d",&t);
            v[x].push_back(t);
        }
    }
    dfs(1,1);
    int ans=0,index=1;
    for(int i=0;i<maxn;i++)
    {
        if(book[i]>ans)
        {
            ans=book[i];
            index=i;
        }
    }
    printf("%d %d\n",ans,index);
    return 0;
}

bfs:

#include<bits/stdc++.h>
using namespace std;
const int maxn=105;
vector<int>v[maxn];
queue<int>q;
int level[maxn],book[maxn];
void bfs()
{
    q.push(1);
    level[1]=1;
    while(!q.empty())
    {
        int t=q.front();
        q.pop();
        book[level[t]]++;
        for(int i=0;i<v[t].size();i++)
        {
            level[v[t][i]]=level[t]+1;
            q.push(v[t][i]);
        }
    }
}
int main()
{
    memset(book,0,sizeof(book));
    memset(level,0,sizeof(level));
    int n,m;
    scanf("%d%d",&n,&m);
    while(m--)
    {
        int x,num;
        scanf("%d%d",&x,&num);
        while(num--)
        {
            int t;
            scanf("%d",&t);
            v[x].push_back(t);
        }
    }
    bfs();
    int ans=0,index=1;
    for(int i=0;i<maxn;i++)
    {
        if(book[i]>ans)
        {
            ans=book[i];
            index=i;
        }
    }
    printf("%d %d\n",ans,index);
    return 0;
}

1095 Cars on Campus (30)排序+思维

【题意】

给出n个车牌号、时间点、进出状态的记录,然后查询k个时间点这时校园内的车辆个数。最后还要输出在校园里面呆的时间最长的车的车牌号,以及呆了多久的时间。如果有多辆车就按照它的字母从小到大输出车牌。如果一个车多次进入未出,取最后一个值;如果一个车多次out未进入,取第一个值。

【解题思路】

本来自己写的代码真的又臭又长还写不下去了qwq coding能力还是没啥提高..这里还是参考了柳神代码

这里每辆车的进出状态用什么记录很重要,直接影响题目的复杂程度,这里用了“in”为1,“out”为-1,为什么呢?看后面就知道啦。

首先对每辆车按照他们的id进行排序,若id相同则按照时间排序,这样可以删去一些无效的时间,重新编排数组car,并且在这过程中可以直接把停留最久时间算出来,用map记录每辆车的停留时间。

然后根据时间进行排序,这里就体现了进出状态记录的重要性,num[i]表示在时间为car[i].time时的车的数量,那么该时刻的车数量就是上个时刻的车数量+car[i].state(如果是“in”开进一辆车就是+1)。

后面就比较好做啦...

【代码】

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e4+5;
int n,m,cnt=0,maxtime=0;
int num[maxn];
struct Node
{
    char id[10];
    int time,state;
}node[maxn],car[maxn];
bool cmp1(Node a,Node b)
{
    return (strcmp(a.id,b.id)==0)?a.time<b.time:(strcmp(a.id,b.id)<0);
}
bool cmp2(Node a,Node b)
{
    return a.time<b.time;
}
map<string,int>mp;
void getlast()
{
    sort(node,node+n,cmp1);
    for(int i=0;i<n-1;i++)
    {
        if(node[i].state==1 && node[i+1].state==-1 && strcmp(node[i].id,node[i+1].id)==0)
        {
            car[cnt++]=node[i];
            car[cnt++]=node[i+1];
            mp[node[i].id]+=node[i+1].time-node[i].time;
            maxtime=max(maxtime,mp[node[i].id]);
        }
    }
}
void getnum()
{
    sort(car,car+cnt,cmp2);
    for(int i=0;i<cnt;i++)
    {
        if(i==0)num[i]+=car[i].state;
        else num[i]=num[i-1]+car[i].state;
    }
}
int main()
{
    int hh,mm,ss;
    scanf("%d%d",&n,&m);
    for(int i=0;i<n;i++)
    {
        char s[5];
        scanf("%s %d:%d:%d %s",node[i].id,&hh,&mm,&ss,s);
        node[i].time=hh*3600+mm*60+ss;
        (s[0]=='i')?node[i].state=1:node[i].state=-1;
    }
    getlast();
    getnum();
    int tmp=0;
    while(m--)
    {
        scanf("%d:%d:%d",&hh,&mm,&ss);
        int t=hh*3600+mm*60+ss,i;
        for(i=tmp;i<cnt;i++)
        {
            if(car[i].time>t)
            {
                printf("%d\n",num[i-1]);
                break;
            }
            else if(i==cnt-1)printf("%d\n",num[i]);
        }
        tmp=i;
    }
    map<string,int>::iterator it;
    for(it=mp.begin();it!=mp.end();it++)
    {
        if(it->second==maxtime)cout<<it->first<<" ";
    }
    printf("%02d:%02d:%02d\n",maxtime/3600,(maxtime%3600)/60,maxtime%60);
}

1096 Consecutive Factors(20)思维

【题意】

一个正整数N的因子中可能存在若干连续的数字。例如630可以分解为3*5*6*7,其中5、6、7就是3个连续的数字。给定任一正整数N,要求编写程序求出最长连续因子的个数,并输出最小的连续因子序列。

【解题思路】

记录n的所有因子,然后依次遍历,更新长连续因子的个数。

【代码】

#include<bits/stdc++.h>
using namespace std;
const int maxn=1<<16+5;
int factor[maxn],cnt;
void init(int n)
{
    cnt=0;
    for(int i=2;i<=sqrt(n+0.5);i++)//sqrt(n+0.5)的原因是存在20=4*5
    {
        if(n%i==0)factor[cnt++]=i;
    }
}
int main()
{
    int n;
    scanf("%d",&n);
    init(n);
    int l,r,len=0,ans=0,sum=1;
    for(int i=0;i<cnt;i++)
    {
        len=0,sum=1;
        while(factor[i+len]==factor[i]+len && sum*factor[i+len]<=n)
        {//判断这些因子是否连续,且相乘不能超过n
            sum*=factor[i+len];
            len++;
            if(n%sum==0 && ans<len)//当n能够被这一段连续的因子整除
            {
                l=i;
                r=i+len-1;
                ans=len;
            }
        }
    }
    if(cnt>=1)
    {
        printf("%d\n%d",ans,factor[l]);
        for(int i=l+1;i<=r;i++)
            printf("*%d",factor[i]);
        printf("\n");
    }
    else printf("1\n%d\n",n);
    return 0;
}

1097 Deduplication on a Linked List(25)链表

【题意】

给一个链表,去重(去掉值或者绝对值相等的),先输出删除后的链表,再输出删除了的链表。

【解题思路】

用结构存储每个节点的信息,s1数组存储保留下的链表的信息,s2数组存储删除的链表的信息,用set记录每个key,当key在set中存在时则将该节点存入s2,否则则存入s1。注意最后输出时最后节点的next要改为-1,并且s2数组只有在cnt2>=1时才输出,不然会有一个测试点过不了。

【代码】

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
struct Node
{
    int addr,key,next;
}node[maxn];
int s1[maxn],s2[maxn];
int main()
{
    int head,n,cnt1=0,cnt2=0;
    scanf("%d%d",&head,&n);
    while(n--)
    {
        int a,b,c;
        scanf("%d%d%d",&a,&b,&c);
        node[a].addr=a;node[a].key=b;node[a].next=c;
    }
    set<int>s;
    while(head!=-1)
    {
        int t=abs(node[head].key);
        if(!s.count(t))
        {
            s1[cnt1++]=node[head].addr;
            s.insert(t);
        }
        else s2[cnt2++]=node[head].addr;
        head=node[head].next;
    }
    for(int i=0;i<cnt1-1;i++)
        printf("%05d %d %05d\n",s1[i],node[s1[i]].key,s1[i+1]);
    printf("%05d %d -1\n",s1[cnt1-1],node[s1[cnt1-1]].key);
    if(cnt2>=1)
    {
        for(int i=0;i<cnt2-1;i++)
            printf("%05d %d %05d\n",s2[i],node[s2[i]].key,s2[i+1]);
        printf("%05d %d -1\n",s2[cnt2-1],node[s2[cnt2-1]].key);
    }

    return 0;
}

1098 Insertion or Heap Sort (25)插入和堆排序

【题意】

给一个待排序序列和一个排序过程中的序列,判断是插入排序还是堆排序,并输出下一步的排序序列。

【解题思路】

插入排序的特点是前一段是有序的,后一段未经排序的序列与原序列相同,那么可以根据这个性质判断是插入排序还是堆排序,如果不是很了解堆排序的话可以戳这里

【代码】

#include<bits/stdc++.h>
using namespace std;
const int maxn=105;
int a[maxn],b[maxn],n;
int check()
{
    for(int i=0;i<n;i++)
        if(a[i]!=b[i])return 0;
    return 1;
}
void maxdown(int start,int end)
{
    int c=start;
    for(int l=c*2+1;l<=end;c=l,l=c*2+1)
    {
        if(l<end && a[l]<a[l+1])l++;
        if(a[c]>=a[l])break;
        else swap(a[c],a[l]);
    }
}
int main()
{
    int idx,flag=1;
    scanf("%d",&n);
    for(int i=0;i<n;i++)
        scanf("%d",&a[i]);
    for(int i=0;i<n;i++)
        scanf("%d",&b[i]);
    for(int i=0;i<n-1;i++)
    {
        if(b[i]>b[i+1])
        {
            idx=i;
            break;
        }
    }
    for(int i=idx+1;i<n;i++)
    {
        if(a[i]!=b[i])
        {
            flag=0;
            break;
        }
    }
    if(flag)
    {
        printf("Insertion Sort\n");
        sort(a,a+idx+2);
    }
    else
    {
        int f=0;
        printf("Heap Sort\n");
        for(int i=n/2-1;i>=0;i--)
            maxdown(i,n-1);
        for(int i=n-1;i>=1;i--)
        {
            if(f==1)break;
            if(check())f=1;
            swap(a[i],a[0]);
            maxdown(0,i-1);
        }
    }
    for(int i=0;i<n;i++)
        (i==0)?printf("%d",a[i]):printf(" %d",a[i]);
}

1099 Build A Binary Search Tree(30)二叉查找树

【题意】

给出一棵二叉搜索树(给出每个结点的左右孩子),且已知根结点为0,求并且给出应该插入这个二叉搜索树的数值,求这棵二叉树的层序遍历。

【解题思路】

已给出二叉查找树的形态需要我们将给出的序列填入这棵二叉查找树,因为二叉查找树的中序遍历刚好是从小到大排序后的序列,所以可以先进行一次中序遍历,在遍历过程中,将这些数填入。最后用一次bfs输出层序序列。

【代码】

#include<bits/stdc++.h>
using namespace std;
const int maxn=105;
int a[maxn],cnt=0;
struct Node
{
    int val;
    int left,right;
}node[maxn];
void inorder(int x)
{
    if(node[x].left==-1 && node[x].right==-1)
    {
        node[x].val=a[cnt++];
        return;
    }
    if(node[x].left!=-1)inorder(node[x].left);
    node[x].val=a[cnt++];
    if(node[x].right!=-1)inorder(node[x].right);
}
void level(int root)
{
    int flag=0;
    queue<int>q;
    q.push(root);
    while(!q.empty())
    {
        int t=q.front();
        q.pop();
        if(t!=-1)
        {
            flag==1?printf(" %d",node[t].val):printf("%d",node[t].val);
            flag=1;
            if(t!=-1)q.push(node[t].left);
            if(t!=-1)q.push(node[t].right);
        }
    }
}
int main()
{
    int n,root;
    scanf("%d",&n);
    for(int i=0;i<n;i++)
        scanf("%d%d",&node[i].left,&node[i].right);
    for(int i=0;i<n;i++)
        scanf("%d",&a[i]);
    sort(a,a+n);
    inorder(0);
    level(0);
    return 0;
}

1100 Mars Numbers(20)字符串处理

【题意】

火星进制为13进制,将地球上相应数字的叫法改成火星上的。

【解题思路】

简单字符串处理,有2个注意点:

1.当数字转换成字符串时,是13的倍数只需输出s2数组中的内容即可。

2.当字符串转换成数字时,若<13则只要去找s1数组对应的下标即可。

【代码】

#include<bits/stdc++.h>
using namespace std;
string s1[]={"tret","jan","feb","mar","apr","may","jun","jly","aug","sep","oct","nov","dec"};
string s2[]={"","tam","hel","maa","huh","tou","kes","hei","elo","syy","lok","mer","jou"};
int main()
{
    int n,x,i,j;
    string s;
    scanf("%d",&n);
    getchar();
    while(n--)
    {
        int flag=0,ans=1;
        getline(cin,s);
        string str="";
        if(isdigit(s[0]))
        {
            x=atoi(s.c_str());
            int t=x/13;
            if(t>0)
            {
                cout<<s2[t];
                flag=1;
            }
            if(t==0 || (t>0 && x%13!=0))(flag==1)?cout<<" "<<s1[x%13]:cout<<s1[x%13];
            cout<<endl;
        }
        else
        {
            for(i=0;i<s.size();i++)
            {
                if(s[i]!=' ')
                    str=str+s[i];
                else break;
            }
            for(j=1;j<13;j++)
            {
                if(str==s2[j])
                {
                    ans=ans*j*13;
                    break;
                }
            }
            str="";
            if(ans==1)ans=0,i=-1;
            for(j=i+1;j<s.size();j++)
            {
                if(s[j]!=' ')
                    str=str+s[j];
                else break;
            }
            for(j=0;j<13;j++)
            {
                if(str==s1[j])
                {
                    ans=ans+j;
                    break;
                }
            }
            printf("%d\n",ans);
        }
    }
    return 0;
}

 

1101 Quick Sort(25)快速排序

【题意】

快速排序中,我们通常采用某种方法取一个元素作为主元,通过交换,把比主元小的元素放到它的左边,比主元大的元素放到它的右边。  给定划分后的N个互不相同的正整数的排列,请问有多少个元素可能是划分前选取的主元?

【解题思路】

其实并不需要用快速排序,很容易就可以得到被选取为主元的元素与排序后元素的位置时相同的,所以只要看这个元素前面的最大的元素如果比它小,就说明它可以被选取为主元。

【代码】

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
int a[maxn],b[maxn],c[maxn];
int main()
{
    int n,flag=0,cnt=0;
    scanf("%d",&n);
    for(int i=0;i<n;i++)
    {
        scanf("%d",&a[i]);
        b[i]=a[i];
    }
    sort(b,b+n);
    int lmax=0;
    for(int i=0;i<n;i++)
    {
        if(b[i]==a[i] && a[i]>lmax)
            c[cnt++]=a[i];
        lmax=max(lmax,a[i]);
    }
    printf("%d\n",cnt);
    if(cnt>=1)
    {
        printf("%d",c[0]);
        for(int i=1;i<cnt;i++)
            printf(" %d",c[i]);
    }
    printf("\n");
    return 0;
}

 

1102 Invert a Binary Tree(25)树的遍历

【题意】

反转一棵二叉树,给出原二叉树的每个结点的左右孩子,输出它的层序和前序遍历。

【解题思路】

其实只要存储的时候就将左右孩子的顺序互换就可以了,根节点就是没有出现过的结点,然后就用bfs输出层序序列,再输出中序序列。

【代码】

#include<bits/stdc++.h>
using namespace std;
const int maxn=15;
struct Node
{
    int left,right,num=-1;
}node[maxn];
int s[maxn],root,flag=0;
void levelorder()
{
    queue<Node>q;
    q.push(node[root]);
    while(!q.empty())
    {
        Node t=q.front();
        q.pop();
        (flag==1)?printf(" %d",t.num):printf("%d",t.num);
        if(t.left!=-1)q.push(node[t.left]);
        if(t.right!=-1)q.push(node[t.right]);
        flag=1;
    }
    printf("\n");
}
void inorder(int x)
{
    if(x==-1)return;
    inorder(node[x].left);
    (flag==1)?printf(" %d",node[x].num):printf("%d",node[x].num);
    flag=1;
    inorder(node[x].right);
}
int main()
{
    int n;
    scanf("%d",&n);
    getchar();
    for(int i=0;i<n;i++)
    {
        char a,b;
        scanf("%c %c",&a,&b);
        node[i].num=i;
        if(isdigit(a))node[i].right=a-'0';
        else node[i].right=-1;
        if(isdigit(b))node[i].left=b-'0';
        else node[i].left=-1;
        getchar();
        s[a-'0']=1;
        s[b-'0']=1;
    }
    for(int i=0;i<n;i++)
    {
        if(!s[i])
        {
            root=i;
            break;
        }
    }
    levelorder();
    flag=0;
    inorder(root);
    printf("\n");
}

1103 Integer Factorization(30)dfs+剪枝

【题意】

将一个数字N拆分成N = n1^P + … nK^P这样的形式,当有多种形式时,取因子和最大的拆分方式。

【解题思路】

先算出小于N的所有p次方的数,然后进行dfs暴力搜索,然后这个时候剪枝就显得非常重要了。

①当因子的数量已经超过k个时,很明显不符合条件。

②当因子的p次方和大于N时,也需要剪枝。

③当因子的数量为k时,但因子的p次方和不等于N,不满足条件。

【代码】

#include<bits/stdc++.h>
using namespace std;
int n,k,p,facans=0;
vector<int>fac,ans,tmp;
void init()
{
   int x=0,y=1;
   while(x<=n)
   {
       fac.push_back(x);
       x=pow(y,p);
       y++;
   }
}
void dfs(int idx,int sum,int numk,int facsum)
{
    if(numk==k)
    {
        if(sum==n && facsum>facans)
        {
            facans=facsum;
            ans=tmp;
        }
        return;
    }
    while(idx>=1)
    {
        if(sum+fac[idx]<=n)
        {
            tmp[numk]=idx;
            dfs(idx,sum+fac[idx],numk+1,facsum+idx);
        }
        if(idx==1)return;
        idx--;
    }
}
int main()
{
    scanf("%d%d%d",&n,&k,&p);
    init();
    tmp.resize(k);
    dfs(fac.size()-1,0,0,0);
    if(facans==0)printf("Impossible");
    else
    {
        printf("%d = ",n);
        for(int i=0;i<k;i++)
            (i==0)?printf("%d^%d",ans[i],p):printf(" + %d^%d",ans[i],p);
    }
    printf("\n");
}

1104 Sum of Number Segments(20)思维

【题意】

求一个序列全排列后的子序列和。

【解题思路】

每个数出现的次数是有规律的,根据n分奇偶讨论一下即可。

比如n=7 可以发现7个数出现的次数为7 12 15 16 15 12 7 即每个数在上一个基础上加上7 5 3 1。

【代码】

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
double a[maxn];
int main()
{
    int n;
    double ans=0;
    scanf("%d",&n);
    a[0]=n*1.0;
    double x=n-2;
    if(n%2)
    {
        for(int i=1;i<=n/2;i++)
        {
            a[i]=a[i-1]+x;
            x-=2;
        }
        for(int i=n-1;i>=(n/2)+1;i--)
            a[i]=a[n-1-i];
    }
    else
    {
        for(int i=1;i<n/2;i++)
        {
            a[i]=a[i-1]+x;
            x-=2;
        }
        for(int i=n-1;i>=n/2;i--)
            a[i]=a[n-1-i];
    }
    for(int i=0;i<n;i++)
    {
        scanf("%lf",&x);
        ans+=x*a[i];
    }
    printf("%.2f\n",ans);
    return 0;
}

1106 Lowest Price in Supply Chain(25)树的遍历

【题意】

提供一棵树,在树根处货物的价格为p,从根结点开始每往下一层,该层货物价格将会在父亲结点的价格上增加r%。求叶子结点出能获得的最低价格以及能提供最低价格的叶子结点数。

【解题思路】

这题我记得已经做过好几次啦,换汤不换药,叶子节点所在的最小深度处的价格最便宜,只要记录该深度时叶子节点的个数即可。

【代码】

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
const int INF=9999999;
vector<int>v[maxn];
int n,cnt=0,minlen=INF;
double price,rate;
void dfs(int x,int len)
{
    if(v[x].size()==0)
    {
        if(len==minlen)
            cnt++;
        else if(minlen>len)
        {
            minlen=len;
            cnt=1;
        }
        return;
    }
    for(int i=0;i<v[x].size();i++)
        dfs(v[x][i],len+1);
}
int main()
{
    scanf("%d%lf%lf",&n,&price,&rate);
    for(int j=0;j<n;j++)
    {
        int num;
        scanf("%d",&num);
        for(int i=0;i<num;i++)
        {
            int t;
            scanf("%d",&t);
            v[j].push_back(t);
        }
    }
    dfs(0,0);
    double ans=price*pow(1+(rate/100),minlen);
    printf("%.4f %d\n",ans,cnt);
    return 0;
}

1107 Social Clusters(30)并查集

【题意】

有n个人,每个人喜欢k个活动,如果两个人有任意一个活动相同,就称为他们处于同一个社交网络。求这n个人一共形成了多少个社交网络。

【解题思路】

将每个人的活动都并在一起,因为只要有一个人的任意一个活动与这个人的任意一个活动相同,则他们就属于同一个社交网络,然后只要有两个人有相同的活动,都将这些活动并在一起,之后只要遍历每个人的活动的根节点,若根节点相同则说明两个人处于同一个社交网络,然后用一个num数组计数。

【代码】

#include<bits/stdc++.h>
using namespace std;
const int maxn=1005;
int pre[maxn],num[maxn];
vector<int>v[maxn];
int findroot(int x)
{
    int r=x;
    while(r!=pre[r])
        r=pre[r];
    return r;
}
void join(int x,int y)
{
    int fx=findroot(x),fy=findroot(y);
    if(fx!=fy)
        pre[fy]=fx;
}
int main()
{
    int n,x,t,t2,cnt=0;
    scanf("%d",&n);
    for(int i=1;i<maxn;i++)
        pre[i]=i;
    for(int i=1;i<=n;i++)
    {
        scanf("%d: ",&x);
        for(int j=0;j<x;j++)
        {
            scanf("%d",&t);
            v[i].push_back(t);
            if(j==0)
            {
                t2=t;
                continue;
            }
            join(t,t2);
            t2=t;
        }
    }
    for(int i=1;i<=n;i++)
    {
        int f=findroot(v[i][0]);
        num[f]++;
    }
    for(int i=0;i<maxn;i++)
    {
        if(num[i]!=0)cnt++;
    }
    sort(num,num+maxn);
    printf("%d\n",cnt);
    if(cnt>=1)
    {
        printf("%d",num[maxn-1]);
        for(int i=maxn-2;num[i]!=0;i--)
            printf(" %d",num[i]);
        printf("\n");
    }
    return 0;
}

1108 Finding Average(20)字符串处理

【题意】

计算合法数据的平均数。

【解题思路】

虽然是20分题,但是细节很多需要注意。

1.计算平均数的前提是数据合法,所以数据必须在[-1000,1000]以内,如果有小数的话小数点后的位数要在两位以内,像3.这样的数据也是合法数据。

2.要注意输出,当只有1个合法数据时和有很多个合法数据时的输出是不一样的。

当然这题还有更好用的方法,不得不说柳神真是太强了qaq

sscanf() :从一个字符串中读进与指定格式相符的数据

sprintf() :字符串格式化命令,主要功能是把格式化的数据写入某个字符串中

【代码】

#include<bits/stdc++.h>
using namespace std;
const int maxn=105;
float a[maxn];
int main()
{
    int n,cnt=0;
    float x;
    string s;
    scanf("%d",&n);
    getchar();
    while(n--)
    {
        int flag=1,flag2=0;
        cin>>s;
        for(int i=0;i<s.size();i++)
        {
            if(s[0]=='-' && isdigit(s[1]) && flag2==0)
            {
                flag2=1;
                continue;
            }
            if(!isdigit(s[i]))
            {
                if(s[i]=='.' &&(s.size()-i-1<=2) )flag=1;
                else flag=0;
                break;
            }
        }
        if(flag)x=atof(s.c_str());
        if(!flag || x<-1000 || x>1000)
            cout<<"ERROR: "<<s<<" is not a legal number"<<endl;
        else a[cnt++]=x;
    }
    float ans=0;
    for(int i=0;i<cnt;i++)
        ans+=a[i];
    if(cnt>1)printf("The average of %d numbers is %.2f\n",cnt,ans/cnt);
    else if(cnt==1)printf("The average of %d number is %.2f\n",cnt,ans/cnt);
    else printf("The average of 0 numbers is Undefined\n");
    return 0;
}

用sscanf(),sprintf()

#include<bits/stdc++.h> 
using namespace std;
int main() {
    int n, cnt = 0;
    char a[50], b[50];
    double temp, sum = 0.0;
    cin >> n;
    for(int i = 0; i < n; i++) {
        scanf("%s", a);
        sscanf(a, "%lf", &temp);
        sprintf(b, "%.2lf",temp);
        int flag = 0;
        for(int j = 0; j < strlen(a); j++) {
            if(a[j] != b[j]) {
                flag = 1;
            }
        }
        if(flag || temp < -1000 || temp > 1000) {
            printf("ERROR: %s is not a legal number\n", a);
            continue;
        } else {
            sum += temp;
            cnt++;
        }
    }
    if(cnt == 1) {
        printf("The average of 1 number is %.2lf", sum);
    } else if(cnt > 1) {
        printf("The average of %d numbers is %.2lf", cnt, sum / cnt);
    } else {
        printf("The average of 0 numbers is Undefined");
    }
    return 0;
}

1109 Group Photo(25)排序

【题意】

根据n个人的身高排序排成k行,多出的人排在最后一排,每行中间第m/2+1个位置的人最高,然后左边比中间低,右边比中间的左边低,若身高相同的则按照名字的字典序排列。

【解题思路】

先根据每个人的身高和姓名排序,用vector存储每一行的人的名字再输出,z记录每一行的人数,x为中间最高的人的序号,u为每一行最左边的人的序号,t是每一行最矮的人的序号,分奇偶数讨论一下,如果这一行的人数为偶数,那么最左边人的序号即为t-1,若为奇数即为t-2。

【代码】

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e4+5;
struct Node
{
    string name;
    int height;
}p[maxn];
bool cmp(Node a,Node b)
{
    return(a.height==b.height)?a.name<b.name:a.height>b.height;
}
int main()
{
    int n,k,t=0,x=0,u,z;
    scanf("%d%d",&n,&k);
    int m=n/k,q=n%k;
    for(int i=0;i<n;i++)
        cin>>p[i].name>>p[i].height;
    sort(p,p+n,cmp);
    for(int i=0;i<k;i++)
    {
        vector<string>v;
        if(i==0)z=m+q;
        else z=m;
        t+=z;
        //printf("x=%d,t=%d,z=%d\n",x,t,z);
        if(z%2)u=t-2;
        else u=t-1;
        for(int j=u;j>x;j-=2)
            v.push_back(p[j].name);
        for(int j=x;j<t;j+=2)
            v.push_back(p[j].name);
        for(int j=0;j<v.size();j++)
            (j==0)?cout<<v[j]:cout<<" "<<v[j];
        printf("\n");
        if(i==0)x=x+m+q;
        else x=x+m;
    }
    return 0;
}

1110 Complete Binary Tree(25)bfs判断完全二叉树

【题意】

给出一个n表示有n个结点,这n个结点为0~n-1,给出这n个结点的左右孩子,求问这棵树是不是完全二叉树。

【解题思路】

注意这里记得用string输入,因为输入的节点数可能大于10,如果一个字符地输就存不下了……刚开始一直在这卡死,还觉得自己没问题。遍历找出没有出现过的结点,这个结点就是根节点,已知根结点和每个结点的左右孩子,根据bfs遍历这棵二叉树,每遍历一个结点就num++,如果发现有-1,判断当前num是否和n相等,如果不等,说明该结点不是最后一个结点,返回NO,否则YES。

参考柳神https://www.liuchuo.net/archives/2158

【代码】

#include<bits/stdc++.h>
using namespace std;
const int maxn=25;
int vis[maxn],n;
struct Node
{
    int left,right;
}node[maxn];

void bfs(int root)
{
    queue<int>q;
    q.push(root);
    int last=0,num=0;
    while(!q.empty())
    {
        int t=q.front();
        q.pop();
        if(t!=-1)
        {
            num++;
            last=t;
        }
        else
        {
            if(num!=n)printf("NO %d\n",root);
            else printf("YES %d\n",last);
            return;
        }
        q.push(node[t].left);
        q.push(node[t].right);
    }
}
int main()
{
    int cnt=0,root;
    scanf("%d",&n);
    memset(vis,0,sizeof(vis));
    for(int i=0;i<n;i++)
    {
        string l,r;
        cin>>l>>r;
        if(l=="-")node[i].left=-1;
        else
        {
            node[i].left=atoi(l.c_str());
            vis[node[i].left]=1;
        }
        if(r=="-")node[i].right=-1;
        else
        {
            node[i].right=atoi(r.c_str());
            vis[node[i].right]=1;
        }
    }
    for(int i=0;i<n;i++)
    {
        if(!vis[i])
        {
            root=i;
            break;
        }
    }
    bfs(root);
    return 0;
}

1112 Stucked Keyboard(20)字符串处理

【题意】

键盘某些键卡住了,按一次重复k次,要求找出可能的键,并且输出正确的字符串顺序。可能的键要求按照被发现的顺序输出。

【解题思路】

1.t1为可能坏了的键,t2为一定没有坏的键,在t1中出现且没有t2中出现的键是一定坏了的键。

2.题中还有一个注意点是要求将可能的键按照被发现的顺序输出,如果忽略这个条件会有两个测试点过不去,所以遍历字符串中的每个字符,看它是否在t1中出现且没有在t2中出现,则加入ans,但为了要防止坏了的键再一次出现,再用一个set记录已经出现过的坏的键,防止重复。

【代码】

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e3+5;
char s[maxn],ans[maxn];
int main()
{
    int k,num=1,cnt=0;
    scanf("%d",&k);
    scanf("%s",s);
    set<char>t1,t2,t;
    set<char>::iterator it;
    int len=strlen(s);
    for(int i=1;i<len;i++)
    {
        if(s[i]==s[i-1])num++;
        else
        {
            if(num%k==0)t1.insert(s[i-1]);
            else t2.insert(s[i-1]);
            num=1;
        }
    }
    if(num%k==0)t1.insert(s[len-1]);
    for(int i=0;i<len;i++)
    {
        if(t1.count(s[i]) && !t2.count(s[i]) && !t.count(s[i]))
        {
            ans[cnt++]=s[i];
            t.insert(s[i]);
        }
    }
    for(int i=0;i<cnt;i++)
        printf("%c",ans[i]);
    printf("\n");
    for(int i=0;i<len;i++)
    {
        printf("%c",s[i]);
        if(t.count(s[i]))i=i+k-1;
    }
    return 0;
}

 

1113 Integer Set Partition(25)水题

【题意】

给一个n个长度的序列,将其分成长度为A和B的序列,要求|A-B|最小,|sumA-sumB|最大。

【解题思路】

排序一下然后分奇偶讨论即可。

【代码】

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
int a[maxn];
int main()
{
    int n;
    scanf("%d",&n);
    for(int i=0;i<n;i++)
        scanf("%d",&a[i]);
    sort(a,a+n);
    if(n%2)printf("1 ");
    else printf("0 ");
    int sum=0;
    for(int i=0;i<n/2;i++)
        sum-=a[i];
    for(int i=n/2;i<n;i++)
        sum+=a[i];
    printf("%d\n",sum);
    return 0;
}

1114 Family Property(25)并查集+排序

【题意】

给定每个人的家庭成员和其自己名下的房产,请你统计出每个家庭的人口数、人均房产面积及房产套数。首先在第一行输出家庭个数(所有有亲属关系的人都属于同一个家庭)。随后按下列格式输出每个家庭的信息:家庭成员的最小编号 家庭人口数 人均房产套数 人均房产面积。其中人均值要求保留小数点后3位。家庭信息首先按人均面积降序输出,若有并列,则按成员编号的升序输出。

【解题思路】

将n个id用结构存储起来,并用vis数组记录这个人是否有出现过,如果没有则这个家庭的人数++,然后将这个人的父母以及孩子都用并查集连接起来,注意因为最后要输出家庭成员的最小编号,所以在合并的时候要判断一下,将最小的id作为根节点。然后将每个id对应的根节点都用set存储,set的大小即是家庭的个数。再遍历n个结构,如果是同个根节点就将人口数、房产套数、人均房产面积分别累加进ans结构数组中,最后按照题意将ans数组排序后输出即可。

【代码】

#include<bits/stdc++.h>
using namespace std;
const int maxn=10005;
int pre[maxn],vis[maxn];
struct Node
{
    int id,estate,area,sum;
}node[maxn];
struct Ans
{
    int id,num;
    double sume,suma,avge,avga;
}ans[maxn];
bool cmp(Ans a,Ans b)
{
    return (a.avga==b.avga)?a.id<b.id:a.avga>b.avga;
}
int findroot(int x)
{
    int r=x;
    while(r!=pre[r])
        r=pre[r];
    return r;
}
void add(int a,int b)
{
    int fx,fy;
    if(a!=-1)fx=findroot(a);
    if(b!=-1)fy=findroot(b);
    if(fx!=fy && a!=-1 && b!=-1)
    {
        if(fx<=fy)pre[fy]=fx;
        else pre[fx]=fy;
    }
}
int main()
{
    int n,cnt=0;
    set<int>s;
    set<int>::iterator it;
    for(int i=1;i<maxn;i++)pre[i]=i;
    scanf("%d",&n);
    for(int i=0;i<n;i++)
    {
        int fa,mo,x,child;
        scanf("%d%d%d%d",&node[i].id,&fa,&mo,&x);
        if(!vis[node[i].id])
        {
            node[i].sum++;
            vis[node[i].id]=1;
        }
        if(!vis[fa] && fa!=-1)
        {
            node[i].sum++;
            vis[fa]=1;
        }
        if(!vis[mo] && mo!=-1)
        {
            node[i].sum++;
            vis[mo]=1;
        }
        add(node[i].id,fa);
        add(node[i].id,mo);
        while(x--)
        {
            scanf("%d",&child);
            if(!vis[child])
            {
                node[i].sum++;
                vis[child]=1;
            }
            add(node[i].id,child);
        }
        scanf("%d%d",&node[i].estate,&node[i].area);
    }
    for(int i=0;i<n;i++)
    {
        int x=findroot(node[i].id);
        s.insert(x);
    }
    printf("%d\n",s.size());
    for(it=s.begin();it!=s.end();it++)
    {
        for(int i=0;i<n;i++)
        {
            int x=findroot(node[i].id);
            if(x==*it)
            {
                ans[cnt].id=*it;
                ans[cnt].num+=node[i].sum;
                ans[cnt].sume+=node[i].estate;
                ans[cnt].suma+=node[i].area;
            }
        }
        cnt++;
    }
    for(int i=0;i<cnt;i++)
    {
        ans[i].avge=ans[i].sume/(ans[i].num*1.0);
        ans[i].avga=ans[i].suma/(ans[i].num*1.0);
    }
    sort(ans,ans+cnt,cmp);
    for(int i=0;i<cnt;i++)
        printf("%04d %d %.3f %.3f\n",ans[i].id,ans[i].num,ans[i].avge,ans[i].avga);
    return 0;
}

 

1116 Come on! Let's C(20)模拟

【题意】

根据n个人的排名发放不同的奖励。然后又q次询问,当询问到的人没有在排名中时输出“Are you kidding”,有的话,第一名输出“Mystery...”,如果排名为奇数则输出“Minion”,其他人则输出“Chocolate”,如果已经查询过了则输出“check”。

【解题思路】

按照题意判断输出即可。

【代码】

#include<bits/stdc++.h>
using namespace std;
int isprime(int x)
{
    if(x==1 || x==0)return 0;
    else if(x==2)return 1;
    for(int i=2;i<=sqrt(x);i++)
    {
        if(x%i==0)return 0;
    }
    return 1;
}
int main()
{
    int n,x;
    map<int,int>m;
    set<int>s;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&x);
        m[x]=i;
    }
    int q;
    scanf("%d",&q);
    while(q--)
    {
        scanf("%d",&x);
        if(!m.count(x))printf("%04d: Are you kidding?\n",x);
        else
        {
            if(s.count(x))printf("%04d: Checked\n",x);
            else
            {
                if(m[x]==1)printf("%04d: Mystery Award\n",x);
                else if(isprime(m[x]))printf("%04d: Minion\n",x);
                else printf("%04d: Chocolate\n",x);
                s.insert(x);
            }
        }
    }
    return 0;
}

1117 Eddington Number(25)水题

【题意】

英国天文学家爱丁顿很喜欢骑车。据说他为了炫耀自己的骑车功力,还定义了一个“爱丁顿数”E,即满足有E天骑车超过E英里的最大整数E。

【解题思路】

因为需要输出最大整数所以先将数组从大到小排序,每过一天e++,当有一天的a[i]<=e+1,e+1的意思是算上当前天,时e即为所求。

【代码】

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
int a[maxn];
bool cmp(int a,int b)
{
    return a>b;
}
int main()
{
    int n,e=0;
    scanf("%d",&n);
    for(int i=0;i<n;i++)
        scanf("%d",&a[i]);
    sort(a,a+n,cmp);
    for(int i=0;i<n;i++)
    {
        if(a[i]<=e+1)break;
        else e++;
    }
    printf("%d\n",e);
    return 0;
}

1118 Birds in Forest(25)并查集

【题意】

一幅画里面的鸟为同一棵树上的,问有多少棵树和多少只鸟,以及对于两只鸟判断是否在同一个树上。

【解题思路】

用并查集连接同一幅图画里的鸟,最后查询时只要看他们的根节点是否为相同即可判断是否在同一树上。

【代码】

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e4+5;
int pre[maxn];
int findroot(int x)
{
    int r=x;
    while(r!=pre[r])
        r=pre[r];
    return r;
}
int add(int x,int y)
{
    int fx=findroot(x);
    int fy=findroot(y);
    if(fx!=fy)pre[fy]=fx;
}
int main()
{
    int n,q,cnt=0;
    set<int>s;
    for(int i=1;i<maxn;i++)pre[i]=i;
    scanf("%d",&n);
    for(int i=0;i<n;i++)
    {
        int m,x,t;
        scanf("%d%d",&m,&x);
        t=x;
        s.insert(x);
        for(int j=1;j<m;j++)
        {
            scanf("%d",&x);
            add(x,t);
            s.insert(x);
            t=x;
        }
    }
    for(int i=1;i<maxn;i++)
    {
        if(s.count(i) && pre[i]==i)
        {
            cnt++;
        }
    }
    printf("%d %d\n",cnt,s.size());
    scanf("%d",&q);
    while(q--)
    {
        int a,b;
        scanf("%d%d",&a,&b);
        int fa=findroot(a),fb=findroot(b);
        if(fa==fb)printf("Yes\n");
        else printf("No\n");
    }
    return 0;
}

 

1120 Friend Numbers(20)set的使用

【题意】

计算将数字的每一位相加后的得到的数。

【解题思路】

这题用set比较方便,因为既可以去重,也按照字典序排列,正好符合题意。

【代码】

#include<bits/stdc++.h>
using namespace std;
int main()
{
    int n;
    set<int>s;
    scanf("%d",&n);
    while(n--)
    {
        int x,sum=0;
        scanf("%d",&x);
        while(x)
        {
            int t=x%10;
            x/=10;
            sum+=t;
        }
        s.insert(sum);
    }
    printf("%d\n",s.size());
    set<int>::iterator it;
    for(it=s.begin();it!=s.end();it++)
        (it==s.begin())?printf("%d",*it):printf(" %d",*it);
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值