【PAT甲级真题整理一】1001~1030

目录

1001 A+B Format(20)a+b,3个一组用“,”隔开

1002 A+B for Polynomials(25)多项式相加

1003 Emergency(25)dfs搜索

1004 Counting Leaves(30)dfs

1005 Spell It Right(20)数位求和

1006 Sign In and Sign Out(25)找最大最小值

1007 Maximum Subsequence Sum(25)最大连续子区间和

1008 Elevator(20)模拟

1009 Product of Polynomials(25)多项式相乘

1010 Radix(25)二分

1011 World Cup Betting(20)模拟

1012 The Best Rank(25)排序

1013 Battle Over Cities(25)并查集

1015 Reversible Primes(20)判断素数

1017 Queueing at Bank (25)模拟

1019 General Palindromic Number(20)回文数

1020 Tree Traversals(25)建树输出层序

1021 Deepest Root(25)并查集+dfs

1022 Digital Library (30)字符串处理

1023 Have Fun with Numbers(20)大数相加

1024 Palindromic Number(25)大数相加

1025 PAT Ranking(排序)

1027 Colors in Mars(20)转换13进制

1028 List Sorting(25)排序

1030 Travel Plan(30)最短路+dfs


1001 A+B Format(20)a+b,3个一组用“,”隔开

【题意】

计算A+B,并且3个一组用“,”隔开。

【解题思路】

自己的刚开始比较麻烦,先将计算后的sum存入一个数组中,先将sum的位数与3做模,不整除的位数先输出,再输出后面的数字,但要考虑最后三位的后面不用“,”。

后来看了大佬的题解,发现不用这么复杂,并学习了一个新的函数。但我这里用的是int数组就不用这个函数了。

sprintf(str,"%d",sum); //将num按指定格式输入到str字符串中。

【代码】

#include<cstdio>
#include<cmath>
#include<iostream>
using namespace std;
int main()
{
	int a,b,sum,c[10]={0},d[10]={0},i=0,s;
	cin>>a>>b;
	sum=a+b;
	if(sum==0){
		cout<<"0"<<endl;
		return 0;
	}
	if(sum<0){
		cout<<"-";
		sum=fabs(sum);
	}
	while(sum){
		int x=sum%10;
		c[i]=x;
		sum=sum/10;
		i++;
	}
	int x=i%3,j,y=x;
	for(j=0;j<i;j++)d[j]=c[i-j-1];
	j=0;
	/*
	while(x){        //注释这部分为自己刚开始写的 
		cout<<d[j];
		x--;j++;
		if(x==0 && i-j!=0)cout<<",";
	}
	int k=0;
	for(;j<i;j++){
		cout<<d[j];
		k++;
		if(k==3 && j!=i-1){
			cout<<",";
			k=0;
		}
	}
	cout<<endl;*/
	for(int j=0;j<i;j++){
		cout<<d[j];
		if((i-j-1)%3==0 && j!=i-1)cout<<",";
	}
	cout<<endl;
	return 0;
 } 

 

1002 A+B for Polynomials(25)多项式相加

【题意】

两个多项式相加。给定每个多项式的系数和指数,求相加后的系数和指数。

【解题思路】

考虑到数据不是很大,直接定义一个数组a,因为多项式的系数一定为整数,所以将数组a的下标作为多项式的系数然后相加即可,输出数组数据不为0的数。

【代码】

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
int main()
{
	int repeat=2,n,max=-1,min=5000;
	double a[2000];
	memset(a,0,sizeof(a));
	while(repeat--){
		cin>>n;
		for(int i=0;i<n;i++){
			int x;double y;
			cin>>x>>y;
			a[x]=a[x]+y;
			if(x>max)max=x;
		}
	}
	int k=0;
	for(int i=0;i<=max+1;i++){
		if(a[i]!=0)k++;
	}
	cout<<k;
	for(int i=max;i>=0;i--){
		if(a[i]!=0)printf(" %d %.1f",i,a[i]);
	}
	cout<<endl;
	return 0;
}

 

1003 Emergency(25)dfs搜索

【题意】

作为一个城市紧急援救队的指挥者,你得到了一个国家的特殊地图。地图上分散着几座城市,城市间用道路连接着。每个城市援救队的数量以及两座城市之间每条道路的长度已经在地图上标出。当某些城市发生了突发事件,需要你的帮助时,你的工作是带领你的队伍尽快的赶到事发现场,与此同时,召集尽可能多的在路上的队伍。并输出最短路径的条数以及救援队伍的最大值。

【解题思路】

深搜,注意这里当已经保存的最短路径比现有路径长时不用往下搜索了,节省时间。

【代码】

#include<bits/stdc++.h>
using namespace std;
const int maxn=505;
const int INF=2147483647;
int edge[maxn][maxn],vis[maxn],a[maxn],cnt=0,ans=0;
int n,m,c1,c2,dis=INF;
void dfs(int x,int l,int y)
{
    vis[x]=1;
    if(l>dis)return;//当路径比现有的最短路径长时不需要往下搜索了
    if(x==c2)
    {
        if(l==dis)//当路径与最短路径相等时
        {
            cnt++;
            if(y>ans)
                ans=y;
        }
        if(l<dis)//当路径比最短路径短时
        {
            cnt=1;
            dis=l;
            ans=y;
        }
        return;
    }
    for(int i=0;i<n;i++)
    {
        if(edge[x][i]!=0 && !vis[i])
        {
            dfs(i,l+edge[x][i],y+a[i]);
            vis[i]=0;
        }
    }
}
int main()
{
    memset(vis,0,sizeof(vis));
    scanf("%d%d%d%d",&n,&m,&c1,&c2);
    for(int i=0;i<n;i++)
        scanf("%d",&a[i]);
    while(m--)
    {
        int u,v,w;
        scanf("%d%d%d",&u,&v,&w);
        edge[u][v]=w;
        edge[v][u]=w;
    }
    dfs(c1,0,a[c1]);
    printf("%d %d\n",cnt,ans);
    return 0;
}

 

1004 Counting Leaves(30)dfs

【题意】

给定一棵树,输出每一层的叶子节点个数。

【解题思路】

用vector存储每个节点的子结点然后进行深搜,当size=0时说明该点是叶子节点,将该层上的叶子节点数+1,并更新树的最大深度。

【代码】

#include<bits/stdc++.h>
using namespace std;
const int maxn=105;
int f[maxn],n,m,maxl;
vector<int>v[maxn];
void dfs(int x,int c)
{
    if(v[x].size()==0)
    {
        if(maxl<c)maxl=c;
        f[c]++;
        return;
    }
    for(int i=0;i<v[x].size();i++)
    {
        dfs(v[x][i],c+1);
    }
}
int main()
{
    scanf("%d%d",&n,&m);
    while(m--)
    {
        int a,b,w;
        scanf("%d%d",&a,&w);
        while(w--)
        {
            scanf("%d",&b);
            v[a].push_back(b);
        }
    }
    dfs(1,0);
    printf("%d",f[0]);
    for(int i=1;i<=maxl;i++)
        printf(" %d",f[i]);
    printf("\n");
    return 0;
}

 

1005 Spell It Right(20)数位求和

【题意】

将一个数的各位数求和后,将每位数用英文表示。

【解题思路】

因为n数据比较大用字符串就好,然后注意细节。

【代码】

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
int main()
{
	string s[10]={"zero","one","two","three","four","five","six","seven","eight","nine"};
	char a[1000];
	int b[1000],j=0;
	memset(b,0,sizeof(b));
	int sum=0;
	scanf("%s",a);
	for(int i=0;i<strlen(a);i++){
		int x=a[i]-'0';
		sum=sum+x;
	}
	//cout<<sum<<endl;
	while(sum){
		int x=sum%10;
		b[j]=x;
		sum=sum/10;
		j++;
	}
	for(int i=j-1;i>0;i--)cout<<s[b[i]]<<" ";
	cout<<s[b[0]]<<endl;
	return 0;
}

 

1006 Sign In and Sign Out(25)找最大最小值

【题意】

给n个人的到达时间和离开时间,找到最先到达的人和最晚离开的人。

【解题思路】

用结构存储每个人的编号和时间,然后把时间化成秒比较方便,然后就是找最大最小值啦。

【代码】

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
struct time{
	string name;
	int utime;
	int ltime;
}s[1000];
int main()
{
	int n,h,m,ss;
	cin>>n;
	char a[100],b[100]; 
	for(int i=0;i<n;i++){
		cin>>s[i].name;
		scanf("%s",a);
		h=((a[0]-'0')*10+a[1]-'0')*3600;
		m=((a[3]-'0')*10+a[4]-'0')*60;
		ss==(a[6]-'0')*10+a[7]-'0';
		s[i].utime=h+m+ss;
		scanf("%s",b);
		h=((b[0]-'0')*10+b[1]-'0')*3600;
		m=((b[3]-'0')*10+b[4]-'0')*60;
		ss==(b[6]-'0')*10+b[7]-'0';
		s[i].ltime=h+m+ss;		
	}
	int min=s[0].utime,max=s[0].ltime,j=0,k=0;
	for(int i=1;i<n;i++){
		if(s[i].utime<min){
			min=s[i].utime;
			j=i;
		}
		if(s[i].ltime>max){
			max=s[i].ltime;
			k=i;
		}
	}
	cout<<s[j].name<<" "<<s[k].name<<endl;
	return 0;
}

 

1007 Maximum Subsequence Sum(25)最大连续子区间和

【题意】

给出n个数,求最大连续的子区间和,并且输出该区间的第一个和最后一个数。如果所有数都小于0,那么则输出0,第一个数和最后一个数。

【解题思路】

因为需要求最大连续子区间和所以最好这个区间里全是正数,即当遇见负数就更新开始和结束的位置,否则就将结束的位置+1,并求和,最后记得更新最大值。

【代码】

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
int main()
{
	int n,flag=0,i;
	cin>>n;
	int a[n];
	for(i=0;i<n;i++){
		cin>>a[i];
		if(a[i]>=0)flag=1;
	}
	if(!flag){
		cout<<"0"<<" "<<a[0]<<" "<<a[n-1]<<endl;
		return 0;
	}
	int end=-1,start=0,mend=0,mstart=0,x=0,max=-9999999;
	for(i=0;i<n;i++){
		if(x<0){
			x=a[i];
			start=i;
			end=i;
		}
		else{
			x=x+a[i];
			end++;
		}
		if(x>max){
			max=x;
			mstart=start;
			mend=end;
		}
	}
	cout<<max<<" "<<a[mstart]<<" "<<a[mend]<<endl;
	return 0;
}

 

1008 Elevator(20)模拟

【题意】

坐电梯,刚开始停在第一层,上升一层需要6s,下降一层需要4s,在每一层都会停留5s,最终不返回第一层,求n个人坐电梯电梯所运行的时间。

【解题思路】

题意理解了就好,这题真的非常水了。

【代码】

#include<cstdio>
#include<iostream>
using namespace std;
int main()
{
	int n,ans=0,x,y=0;
	cin>>n;
	for(int i=0;i<n;i++){
		cin>>x;
		if(x-y>0)ans=ans+(x-y)*6+5;
		else ans=ans+(y-x)*4+5;
		y=x;
	}
	cout<<ans<<endl;
	return 0;
}

 

 

1009 Product of Polynomials(25)多项式相乘

【题意】

给两个多项式的项数、系数、指数,求两个多项式相乘后的项数、系数、指数。

【解题思路】

用数组的下标存储多项式的系数,数组的值存储多项式的指数,然后当两个数组的相同下标的值都不为0时,指数相加,存入另一个数组c,最后输出数组中不为0的个数,以及将他们的下标和值输出即可。

【代码】

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
int main()
{
	int max1=0,max2=0,max3=0,x,i,j;
	double a[2005],b[2005],c[2005],y;
	memset(a,0,sizeof(a));
	memset(b,0,sizeof(b));
	memset(c,0,sizeof(b));
	int n;
	cin>>n;
	for(i=0;i<n;i++){
		cin>>x>>y;
		a[x]=y;
		if(x>max1)max1=x;
	}
	cin>>n;
	for(i=0;i<n;i++){
		cin>>x>>y;
		b[x]=y;
		if(x>max2)max2=x;
	}
	for(i=0;i<=max1+1;i++){
		for(j=0;j<=max2+1;j++){
			if(a[i]!=0 && b[j]!=0){
				int z=i+j;
				c[z]=c[z]+a[i]*b[j];
				if(z>max3)max3=z;
			}
		}
	}
	int k=0;
	for(i=0;i<=max3+1;i++){
		if(c[i]!=0)k++;
	}
	cout<<k;
	for(i=max3+1;i>=0;i--){
		if(c[i]!=0)printf(" %d %.1f",i,c[i]);
	}
	cout<<endl;
	return 0;
}

 

1010 Radix(25)二分

【题意】

给出N1,N2,tag,radix,tag表示第几个数是radix进制的,看另一个数在某种进制下是否可以与它相等。

【解题思路】

这题有19个测试点,可以说是细节十分多了qaq需要用到二分,关键是上限和下限的问题。

下限:这个数中出现的最大数+1(这个应该好理解,比如10进制里最大的数是9)

上限:这里上限不是36!不是36!是取下限和另一个数中的较大者

【代码】

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
LL covert(string s,LL radix)
{
    LL sum=0;
    for(int i=0;i<s.length();i++)
    {
        if(isdigit(s[i]))
            sum=sum*radix+s[i]-'0';
        else
            sum=sum*radix+s[i]-'a'+10;
    }
    return sum;
}
LL binary(string s,LL x)
{
    char c=*max_element(s.begin(),s.end());
    LL l,r;
    l=(isdigit(c)?c-'0':c-'a'+10)+1;
    r=max(l,x);
    while(l<=r)
    {
        LL mid=(l+r)/2;
        LL t=covert(s,mid);
        if(t==x)return mid;
        else if(t>x || t<0)r=mid-1;//t<0是因为t太大超限了会返回一个小于0的数
        else l=mid+1;
    }
    return -1;
}
int main()
{
    string s1,s2;
    LL tag,radix,ans;
    cin>>s1>>s2>>tag>>radix;
    ans=(tag==1)?binary(s2,covert(s1,radix)):binary(s1,covert(s2,radix));
    if(ans==-1)
        printf("Impossible\n");
    else
        printf("%lld\n",ans);
    return 0;
}

 

1011 World Cup Betting(20)模拟

【题意】

给出三行数据,代表三场比赛。每行有三个浮点整数,从左至右分别代表W(Win)、T(Tie)、L(Lost)。现在需要从每行的 W、T、L 中选择最大的数,并输出三行各自选择的是哪一个,最后输出最大收益。

【解题思路】

找出每一行的最大值的下标对应的‘W’,'T','L',然后根据 (4.1*3.0*2.5*65%-1)*2 = 37.98这个公式计算答案,即每一行的最大值相乘*0.65-1,然后再乘2,最后直接保留两位小数即可,答案是错的。

【代码】

#include<bits/stdc++.h>
using namespace std;
int main()
{
    char s[]={'W','T','L'};
    double a[3][3];
    double ans=1;
    for(int i=0;i<3;i++)
    {
        double max=0;
        int t=0;
        for(int j=0;j<3;j++)
        {
            scanf("%lf",&a[i][j]);
            if(max<a[i][j])
            {
                max=a[i][j];
                t=j;
            }
        }
        printf("%c ",s[t]);
        ans*=max;
    }
    ans=(ans*0.65-1)*2;
    printf("%.2f\n",ans);
    return 0;
}

 

1012 The Best Rank(25)排序

【题意】

现已知n个考生的3门分数,平均分可以按照这三门算出来。然后分别对这四个分数从高到低排序,这样对每个考生来说有4个排名。k个查询,对于每一个学生id,输出当前id学生的最好的排名和它对应的分数,如果名次相同,按照A>C>M>E的顺序输出。如果当前id不存在,输出N/A。

【解题思路】

分别写4个函数简单排序就可以啦,记得在结构体里更新每个考生最好的排名。

【代码】

#include<bits/stdc++.h>
using namespace std;
int n,m;
struct student
{
    string sno;
    int score[4];
    int rank1;
    int cno;
    int bestrank=5050;
}st[2005];
bool cmp1(student a,student b)
{
    return a.score[3]>b.score[3];
}
bool cmp2(student a,student b)
{
    return a.score[0]>b.score[0];
}
bool cmp3(student a,student b)
{
    return a.score[1]>b.score[1];
}
bool cmp4(student a,student b)
{
    return a.score[2]>b.score[2];
}
void ranking(int k)
{
    st[0].rank1=1;
    if(st[0].rank1<st[0].bestrank)
    {
        st[0].bestrank=st[0].rank1;
        st[0].cno=k;
    }
    for(int i=1;i<n;i++)
    {
        if(st[i].score[k]==st[i-1].score[k])
            st[i].rank1=st[i-1].rank1;
        else st[i].rank1=i+1;
        if(st[i].rank1<st[i].bestrank)
        {
            st[i].bestrank=st[i].rank1;
            st[i].cno=k;
        }
    }
}
int main()
{
    string s1;
    set<string>s;
    scanf("%d%d",&n,&m);
    for(int i=0;i<n;i++)
    {
        cin>>st[i].sno;
        scanf("%d%d%d",&st[i].score[0],&st[i].score[1],&st[i].score[2]);
        st[i].score[3]=(st[i].score[0]+st[i].score[1]+st[i].score[2])/3;
        s.insert(st[i].sno);
    }
    sort(st,st+n,cmp1);
    ranking(3);
    sort(st,st+n,cmp2);
    ranking(0);
    sort(st,st+n,cmp3);
    ranking(1);
    sort(st,st+n,cmp4);
    ranking(2);
    while(m--)
    {
        cin>>s1;
        if(!s.count(s1))
        {
            printf("N/A\n");
            continue;
        }
        char ch[]={'C','M','E','A'};
        for(int i=0;i<n;i++)
        {
            if(st[i].sno==s1)
                printf("%d %c\n",st[i].bestrank,ch[st[i].cno]);
        }
    }
    return 0;
}

1013 Battle Over Cities(25)并查集

【题意】

给出n个城市之间有相互连接的m条道路,当删除一个城市和其连接的道路的时候,问其他几个剩余的城市至少要添加多少个路线才能让它们重新变为连通图。

【解题思路】

添加的最少的路线,就是他们的连通分量数-1,因为当a个互相分立的连通分量需要变为连通图的时候,只需要添加a-1个路线,就能让他们相连。所以当删去一个城市时图中的边数最多为num=n-2,当除去这个顶点的其他顶点每当有一条边相连时则num--,最后剩下的则为最少的路线使其变成连通图。

【代码】

#include<bits/stdc++.h>
using namespace std;
const int maxn=500005;
int pre[maxn];
struct route
{
    int x,y;
}r[maxn];
int find(int x)
{
    int r=x;
    while(pre[r]!=r)
        r=pre[r];
    int i=x,j;
    while(i!=r)
    {
        j=pre[i];
        pre[i]=r;
        i=j;
    }
    return r;
}
int main()
{
    int n,m,k;
    scanf("%d%d%d",&n,&m,&k);
    for(int i=0;i<m;i++)
        scanf("%d%d",&r[i].x,&r[i].y);
    while(k--)
    {
        int x,num=n-2;
        scanf("%d",&x);
        for(int i=0;i<=n;i++)pre[i]=i;
        for(int i=0;i<m;i++)
        {
            if(r[i].x!=x && r[i].y!=x)
            {
                int p1=find(r[i].x);
                int p2=find(r[i].y);
                if(p1!=p2)
                {
                    pre[p2]=p1;
                    num--;
                }
            }
        }
        printf("%d\n",num);
    }
    return 0;
}

 

1015 Reversible Primes(20)判断素数

【题意】

如果一个数本身是素数,而且在d进制下反转后的数在十进制下也是素数,就输出Yes,否则就输出No。

【解题思路】

简单题,只要会判断素数+进制转换就可以啦。

【代码】

#include<bits/stdc++.h>
using namespace std;
int isprime(int x)
{
    if(x==0 ||x==1)return 0;
    for(int i=2;i<=sqrt(x);i++)
    {
        if(x%i==0)return 0;
    }
    return 1;
}
int main()
{
    int n,d;
    while(~scanf("%d",&n) && n>=0)
    {
        scanf("%d",&d);
        if(!isprime(n))
        {
            printf("No\n");
            continue;
        }
        int num=0;
        while(n)
        {
            int x=n%d;
            num=num*d+x;
            n/=d;
        }
        //printf("%d\n",num);
        if(isprime(num))printf("Yes\n");
        else printf("No\n");
    }
    return 0;
}

 

1017 Queueing at Bank (25)模拟

【题意】

模拟银行的作息,银行8:00-17:00营业,8:00之前到的顾客都需要等到8:00才能被服务,17:00以后到的顾客都不能被服务且不计入平均等待时间内,但是只要是17:00及以前到的不管他的服务时间是否超出17:00都能被服务。

【解题思路】

先排序,按来的时间的早晚进行排序,若相同则按服务时间排序,服务时间越短越靠前。然后只要找每个窗口最早的有空时间就好了,当窗口的时间大于顾客来的时间时要累加等待时间,否在则不累加。

另外为了方便都转换为秒来实现,最后输出/60就可以了。

【代码】

#include<bits/stdc++.h>
using namespace std;
const int maxn=10005;
struct customer
{
    int t,w;
}c[maxn];
bool cmp(customer a,customer b)
{
    return a.t<b.t;
}
int main()
{
    int n,k,hh,mm,ss,a[105],w;
    int t1=8*3600,t2=17*3600,ans=0;
    scanf("%d%d",&n,&k);
    for(int i=0;i<k;i++)
        a[i]=t1;
    int num=n;
    for(int i=0;i<n;i++)
    {
        scanf("%d:%d:%d",&hh,&mm,&ss);
        scanf("%d",&w);
        c[i].t=hh*3600+mm*60+ss;
        c[i].w=w*60;
    }
    sort(c,c+n,cmp);
    for(int i=0;i<n;i++)
    {
        int min1=a[0],p=0;
        if(c[i].t>t2)
        {
            num--;
            continue;
        }
        for(int j=1;j<k;j++)
        {
            if(min1>a[j])
            {
                min1=a[j];
                p=j;
            }
        }
        if(min1>=c[i].t)
        {
            ans+=min1-c[i].t;
            a[p]+=c[i].w;
        }
        else
            a[p]=c[i].t+c[i].w;
        //printf("ans=%d,a[%d]=%d\n",ans,p,a[p]);
    }
    double avg=ans*1.0/(60*num*1.0);
    printf("%.1f\n",avg);
    return 0;
}

 

1019 General Palindromic Number(20)回文数

【题意】

给定一个数n和b,判断n在b进制下是否是回文数,并输出n在b进制下的数。

【解题思路】

主要在于如何计算n在b进制下的数,其实还是简单滴,但是要注意a[]记录的数据是n在b进制下的数的逆序。

【代码】

#include<bits/stdc++.h>
using namespace std;
const int maxn=105;
int a[maxn];
int main()
{
    int n,b,k=0;
    memset(a,0,sizeof(a));
    scanf("%d%d",&n,&b);
    while(n)
    {
        int x=n%b;
        a[k++]=x;
        n/=b;
    }
    int flag=1;
    for(int i=0;i<k/2;i++)
    {
        if(a[i]!=a[k-i-1])
        {
            flag=0;
            break;
        }
    }
    if(flag)printf("Yes\n");
    else printf("No\n");
    printf("%d",a[k-1]);
    for(int i=k-2;i>=0;i--)
        printf(" %d",a[i]);
    printf("\n");
    return 0;
}

 

1020 Tree Traversals(25)建树输出层序

【题意】

已知一棵树的后序和中序,输出树的层序。

【解题思路】

已知后序序列:2 3 1 5 7 6 4(左右根)

中序序列:1 2 3 4 5 6 7(左根右)

可知后序序列的最后一个结点肯定是整棵树的根节点,后而对应的中序序列的根节点在中序序列的中间,此例为4,所以就将树分成左子树(1 2 3)和右子树(5 6 7)。具体实现方法为,设中序序列为in,后序序列为post,设置一个游标变量cur,左右范围变量left、right,cur作为一个全局变量,每次在post中取出一个根,就让cur自减1,首先把拿到的根定位在inOrder中,设根所在的索引为Index,首先建立当前根节点T,然后生成左子树范围left到Index-1和右子树范围Index+1到right,注意由于后序序列倒着走线碰到右子树,因此应该先递归T->right,再递归T->left,当发现left比right大时,说明没有子树,直接返回NULL,当发现left=right时,说明这是一个叶子结点,将结点的left和right置为NULL然后返回,最后一次递归返回时返回的是第一次创建的根结点,也就是整棵树的根,这时便得到了完整的二叉树。

【代码】

#include<bits/stdc++.h>
using namespace std;
const int maxn=35;
int post[maxn],in[maxn],cur,n,flag=1;
typedef struct TreeNode
{
    struct TreeNode* left;
    struct TreeNode* right;
    int num;
}*tree,node;
int findIndex(int x)
{
    for(int i=0;i<n;i++)
    {
        if(in[i]==x)return i;
    }
    return -1;
}
void buildtree(tree &T,int left,int right)
{
    if(right<left)return;
    int root=post[cur];
    cur--;
    int Index=findIndex(root);
    T=new node();
    T->num=root;
    if(right==left)
    {
        T->left=NULL;
        T->right=NULL;
    }
    else
    {
        buildtree(T->right,Index+1,right);
        buildtree(T->left,left,Index-1);
    }
}
void level(tree &T)
{
    if(T==NULL)return;
    queue<tree>q;
    q.push(T);
    while(!q.empty())
    {
        tree c=q.front();
        q.pop();
        if(flag)
        {
            printf("%d",c->num);
            flag=0;
        }
        else printf(" %d",c->num);
        if(c->left!=NULL)
            q.push(c->left);
        if(c->right!=NULL)
            q.push(c->right);
    }
}
int main()
{
    tree T;
    scanf("%d",&n);
    for(int i=0;i<n;i++)
        scanf("%d",&post[i]);
    for(int i=0;i<n;i++)
        scanf("%d",&in[i]);
    cur=n-1;
    buildtree(T,0,n-1);
    level(T);
    printf("\n");
}

不建树版:

#include<bits/stdc++.h>
using namespace std;
const int maxn=10005;
int post[maxn],in[maxn],level[maxn];
void levelorder(int root,int start,int end,int index)
{
    if(start>end)return;
    int i=start;
    while(i<end && in[i]!=post[root])i++;
    level[index]=post[root];
    levelorder(root-1-end+i,start,i-1,2*index+1);
    levelorder(root-1,i+1,end,2*index+2);
}
int main()
{
    int n,num=0;
    scanf("%d",&n);
    for(int i=0;i<n;i++)
        scanf("%d",&post[i]);
    for(int i=0;i<n;i++)
        scanf("%d",&in[i]);
    levelorder(n-1,0,n-1,0);
    int i=0;
    while(num<n)
    {
        if(level[i])
        {
            num==0?printf("%d",level[i]):printf(" %d",level[i]);
            num++;
        }
        i++;
    }
    printf("\n");
    return 0;
}

 

1021 Deepest Root(25)并查集+dfs

【题意】

给出n个结点(1~n)之间的n条边,问是否能构成一棵树,如果不能构成则输出它有的连通分量个数,如果能构成一棵树,输出能构成最深的树的高度时,树的根结点。如果有多个,按照从小到大输出。

【解题思路】

用并查集判断该幅图是否有多个连通分量,如果有则输出相应内容,直接退出。如果没有,则说明这幅图课构成一棵树,那么只需dfs搜索以每个节点为根节点时最长可以达到的长度,然后更新最大值,最后将这些节点的信息和最大长度存储到结构中排序,注意当有多个最大长度的节点时,需要按字典序输出节点序号。

【代码】

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e4+5;
vector<int>v[maxn];
int vis[maxn],max1,pre[maxn];
struct tree
{
    int num,sum;//节点编号,节点最大长度
}t[maxn];
void dfs(int x,int num)
{
    vis[x]=1;
    for(int i=0;i<v[x].size();i++)
    {
        int t=v[x][i];
        if(!vis[t])
        {
            dfs(t,num+1);
            max1=max(num,max1);
        }
    }
}
bool cmp(tree a,tree b)
{
    return (a.sum==b.sum)?a.num<b.num:a.sum>b.sum;
}
int findroot(int x)
{
    int r=x;
    while(pre[r]!=r)
        r=pre[r];
    int i=x,j;
    while(i!=r)
    {
        j=pre[i];
        pre[i]=r;
        i=j;
    }
    return r;
}
int main()
{
    int n;
    scanf("%d",&n);
    int m=n-1;
    for(int i=1;i<=n;i++)pre[i]=i;
    while(m--)
    {
        int a,b;
        scanf("%d%d",&a,&b);
        v[a].push_back(b);
        v[b].push_back(a);
        int x=findroot(a),y=findroot(b);
        if(x!=y) pre[y]=x;
    }
    int ans=0;
    for(int i=1;i<=n;i++)
    {
        if(pre[i]==i)ans++;
    }
    if(ans>1)
    {
        printf("Error: %d components\n",ans);
        return 0;
    }
    for(int i=1;i<=n;i++)
    {
        int num=1;
        max1=num;
        memset(vis,0,sizeof(vis));
        dfs(i,num);
        t[i].num=i;
        t[i].sum=max1;
    }
    sort(t+1,t+n+1,cmp);
    printf("%d\n",t[1].num);
    for(int i=2;i<=n;i++)
    {
        if(t[i].sum==t[1].sum)printf("%d\n",t[i].num);
        else break;
    }
    return 0;
}

1022 Digital Library (30)字符串处理

【题意】

根据提供的书籍信息查找书籍编号,需要从小到大输出。

【解题思路】

用结构存一下每本书的信息,然后暴力找就可以啦。

这里用map存储了书的编号方便查找,然后书的出版社、作者等信息都是用string数组存储的这样代码会比较短。

坑点:最后输出的ID要补0,哭辽,最后两个测试点一直过不去没想到是因为这个...

【代码】

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e4+5;
int n,sno,m;
string choice;
struct Node
{
    string str[5];
}book[maxn];
map<int,int>mp;
set<int>st;
void makeans(int t,string s)
{
    for(int i=0;i<n;i++)
    {
        if(t==2)
        {
            if(book[i].str[t].find(s)!=book[i].str[t].npos)st.insert(mp[i]);
            continue;
        }
        if(book[i].str[t]==s)st.insert(mp[i]);
    }
    set<int>::iterator it;
    if(st.empty())printf("Not Found\n");
    else
    {
        for(it=st.begin();it!=st.end();it++)
            printf("%07d\n",*it);
    }
}
int main()
{
    scanf("%d",&n);
    for(int i=0;i<n;i++)
    {
        scanf("%d",&sno);
        mp[i]=sno;
        getchar();
        for(int j=0;j<5;j++)
            getline(cin,book[i].str[j]);
    }
    scanf("%d",&m);
    getchar();
    while(m--)
    {
        st.clear();
        getline(cin,choice);
        cout<<choice<<endl;
        makeans(choice[0]-'0'-1,choice.substr(3));
    }
}

 

1023 Have Fun with Numbers(20)大数相加

【题意】

某个数乘以两倍之后看每位数的个数是否与原数相同。比如123456789,num[1]~num[9]均等于1,乘2倍后246913578,num[1]~num[9]也均等于1。

【解题思路】

这题有3个注意点

1.因为n的位数最大为20位,而long long只有19位,并且考虑到乘2倍之后要进位的关系,所以需要用字符串处理。

2.如果进位后,每位数与原来的个数肯定不同,这个要单独拿出来考虑,不然可能存在某个数,乘以2倍后数字中会有0,但其他各位数的个数都与原数相同的情况。

3.注意最后输出的时候不管Yes还是No都要把乘以两倍后的数输出。

【代码】

#include<bits/stdc++.h>
using namespace std;
const int maxn=25;
char a[maxn],b[maxn],c[maxn];
int num1[10],num2[10];
int main()
{
    memset(num1,0,sizeof(num1));
    memset(num2,0,sizeof(num2));
    memset(c,0,sizeof(c));
    scanf("%s",a);
    int l=strlen(a);
    for(int i=0;i<l;i++)
        num1[a[i]-'0']++;
    for(int i=0;i<l;i++)
        b[i]=a[l-i-1];
    int t=0,i;
    for(i=0;i<l;i++)
    {
        int x=b[i]-'0'+b[i]-'0'+t;
        t=x/10;
        c[i]=x%10+'0';
    }
    int l2=i,flag=1;
    if(t!=0)
    {
        c[l2++]=t+'0';
        flag=0;
    }
    if(flag)
    {
        for(i=0;i<l2;i++)
            num2[c[i]-'0']++;
        for(i=1;i<=9;i++)
        {
            if(num1[i]!=num2[i])
            {
                flag=0;
            break;
            }
        }
    }
    if(!flag)printf("No\n");
    else printf("Yes\n");
    for(i=l2-1;i>=0;i--)
        printf("%c",c[i]);
    printf("\n");
    return 0;
}

 

1024 Palindromic Number(25)大数相加

【题意】

给定n和step,判断n是否为回文数,若不是,则将n反转后再加n,看其是不是回文数,若是则输出步数,若不是继续上述操作,当操作步数大于step时输出step。

【解题思路】

数据很大还是需要大数相加,再注意一些细节即可。

【代码】

#include<bits/stdc++.h>
using namespace std;
const int maxn=55;
char a[maxn],b[maxn],c[maxn],lc;
int judge()
{
    int l=strlen(a),flag=1;
    for(int i=0;i<l/2;i++)
    {
        if(a[i]!=a[l-i-1])
            return 0;
    }
    if(flag)return 1;
}
void add()
{
    int l=strlen(a),t=0,i;
    for(i=0;i<l;i++)
    {
        int x=a[i]-'0'+b[i]-'0'+t;
        c[i]=x%10+'0';
        t=x/10;
    }
    lc=i;
    if(t!=0)c[lc++]=t+'0';
}
int main()
{
    int m,flag=1,i;
    scanf("%s%d",a,&m);
    for(i=0;i<m;i++)
    {
        lc=0;
        memset(c,0,sizeof(c));
        if(judge())break;
        int l=strlen(a);
        for(int j=0;j<l;j++)
            b[j]=a[l-j-1];
        add();
        for(int j=lc-1,k=0;j>=0;j--,k++)
            a[k]=c[j];
    }
    printf("%s\n%d\n",a,i);
    return 0;
}

 

1025 PAT Ranking(排序)

【题意】

分成K组,每组N个人,输出每个人在每组的排名,以及其的组别。最后再按字典序顺序输出整体的排名。

【解题思路】

每组数据排个序记录局部排名,再整体排序记录整体排名,注意最后输出时当分数相同时,序号越小越靠前。

【代码】

#include<bits/stdc++.h>
using namespace std;
const int maxn=300005;
struct regist
{
    string sno;
    int score;
    int fr,ln,lr;
}r[maxn];
bool cmp(regist a,regist b)
{
    return (a.score==b.score)?a.sno<b.sno:a.score>b.score;
}
int main()
{
    int n,k,t=0;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&k);
        for(int j=t;j<t+k;j++)
        {
            cin>>r[j].sno>>r[j].score;
            r[j].ln=i;
        }
        sort(r+t,r+t+k,cmp);
        int p=1,q=1;
        r[t].lr=p;
        for(int j=t+1;j<t+k;j++)
        {
            if(r[j-1].score==r[j].score)
            {
                r[j].lr=p;
                q++;
            }
            else
            {
                p+=q;
                r[j].lr=p;
                q=1;
            }
        }
        t+=k;
    }
    sort(r,r+t,cmp);
    int p=1,q=1;
    r[0].fr=p;
    for(int i=1;i<t;i++)
    {
        if(r[i-1].score==r[i].score)
        {
            r[i].fr=p;
            q++;
        }
        else
        {
            p+=q;
            r[i].fr=p;
            q=1;
        }
    }
    printf("%d\n",t);
    for(int i=0;i<t;i++)
    {
        cout<<r[i].sno;
        printf(" %d %d %d\n",r[i].fr,r[i].ln,r[i].lr);
    }
    return 0;
}

 

1027 Colors in Mars(20)转换13进制

【题意】

给出3个数字分别表示十进制下的r,g,b3种颜色,将其转换成13进制,并开头加上#打印出。

【解题思路】

感觉PAT好多进制转换问题...注意细节。

【代码】

#include<bits/stdc++.h>
using namespace std;
char r[2],g[2],b[2];
char trans(int x)
{
    return (x-10)+'A';
}
void f(int x,int t)
{
    int i=0;
    char c;
    while(x)
    {
        int a=x%13;
        if(a>=10)c=trans(a);
        else c=a+'0';
        if(t==1)r[i++]=c;
        else if(t==2)g[i++]=c;
        else b[i++]=c;
        x/=13;
    }
}
int main()
{
    int a1,a2,a3;
    memset(r,'0',sizeof(r));
    memset(g,'0',sizeof(g));
    memset(b,'0',sizeof(b));
    scanf("%d%d%d",&a1,&a2,&a3);
    f(a1,1);
    f(a2,2);
    f(a3,3);
    printf("#");
    for(int i=1;i>=0;i--)
        printf("%c",r[i]);
    for(int i=1;i>=0;i--)
        printf("%c",g[i]);
    for(int i=1;i>=0;i--)
        printf("%c",b[i]);
    printf("\n");
    return 0;
}

 

1028 List Sorting(25)排序

【题意】

将n个人根据第c列排序,当姓名和成绩相同时按照学号从小到大排。

【解题思路】

不要偷懒用string!最后一个测试点会超时!还是老老实实用char吧,strcmp()函数也很方便的。

【代码】

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
struct student
{
    int sno;
    char name[15];
    int grade;
}s[maxn];
bool cmp1(student a,student b)
{
    return a.sno<b.sno;
}
bool cmp2(student a,student b)
{
    return (strcmp(a.name,b.name)==0)?a.sno<b.sno:(strcmp(a.name,b.name)<0);
}
bool cmp3(student a,student b)
{
    return (a.grade==b.grade)?a.sno<b.sno:a.grade<b.grade;
}
int main()
{
    int n,c;
    scanf("%d%d",&n,&c);
    for(int i=0;i<n;i++)
        scanf("%d%s%d",&s[i].sno,&s[i].name,&s[i].grade);
    if(c==1)sort(s,s+n,cmp1);
    else if(c==2)sort(s,s+n,cmp2);
    else sort(s,s+n,cmp3);
    for(int i=0;i<n;i++)
        printf("%06d %s %d\n",s[i].sno,s[i].name,s[i].grade);
    return 0;
}

 

1030 Travel Plan(30)最短路+dfs

【题意】

求起点到终点的最短路径最短距离和花费,要求首先路径最短,其次花费最少,要输出完整路径。

【解题思路】

先通过dijkstra算法求出最短路径,并用vector记录该路径,然后dfs搜索几条最短路径中的最小花费,因为记录最小花费时是逆序记录的,所以最后输出路径时需要注意。

【代码】

#include<bits/stdc++.h>
using namespace std;
const int maxn=505;
const int INF=0x3f3f3f3f;
int n,m,s,d,mincost=INF;
int edge[maxn][maxn],dis[maxn],Cost[maxn][maxn];
vector<int>pre[maxn];
vector<int>temppath,path;
void dfs(int v)
{
    temppath.push_back(v);
    if(v==s)
    {
        int tempcost=0;
        for(int i=temppath.size()-1;i>=1;i--)
        {
            int x=temppath[i],y=temppath[i-1];
            tempcost+=Cost[x][y];
        }
        if(tempcost<mincost)
        {
            mincost=tempcost;
            path=temppath;
        }
        temppath.pop_back();
        return;
    }
    for(int i=0;i<pre[v].size();i++)
        dfs(pre[v][i]);
    temppath.pop_back();
}
void dijkstra()
{
    int vis[maxn];
    memset(vis,0,sizeof(vis));
    for(int i=0;i<n;i++)
        dis[i]=INF;
    dis[s]=0;
    pre[s].push_back(s);
    while(1)
    {
        int v=-1;
        for(int i=0;i<n;i++)
        {
            if(!vis[i] && (v==-1 || dis[i]<dis[v]))
                v=i;
        }
        if(v==-1)break;
        vis[v]=1;
        for(int i=0;i<n;i++)
        {
            if(dis[i]>dis[v]+edge[v][i])
            {
                dis[i]=dis[v]+edge[v][i];
                pre[i].clear();
                pre[i].push_back(v);
            }
            else if(dis[i]==dis[v]+edge[v][i])
                pre[i].push_back(v);
        }
    }

}
int main()
{
    scanf("%d%d%d%d",&n,&m,&s,&d);
    for(int i=0;i<maxn;i++)
        for(int j=0;j<maxn;j++)
            edge[i][j]=INF;
    while(m--)
    {
        int a,b,dist,cost;
        scanf("%d%d%d%d",&a,&b,&dist,&cost);
        edge[a][b]=edge;[b][a]=dist;
        Cost[a][b]=Cost;[b][a]=cost;
    }
    dijkstra();
    dfs(d);
    printf("%d",path[path.size()-1]);
    for(int i=path.size()-2;i>=0;i--)
        printf(" %d",path[i]);
    printf(" %d %d\n",dis[d],mincost);
    return 0;
}

 

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值