1. 程式人生 > >【PAT甲級真題整理一】1001~1030

【PAT甲級真題整理一】1001~1030

目錄

【題意】

計算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;
 } 

【題意】

兩個多項式相加。給定每個多項式的係數和指數,求相加後的係數和指數。

【解題思路】

考慮到資料不是很大,直接定義一個數組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;
}

【題意】

作為一個城市緊急援救隊的指揮者,你得到了一個國家的特殊地圖。地圖上分散著幾座城市,城市間用道路連線著。每個城市援救隊的數量以及兩座城市之間每條道路的長度已經在地圖上標出。當某些城市發生了突發事件,需要你的幫助時,你的工作是帶領你的隊伍儘快的趕到事發現場,與此同時,召集儘可能多的在路上的隊伍。並輸出最短路徑的條數以及救援隊伍的最大值。

【解題思路】

深搜,注意這裡當已經儲存的最短路徑比現有路徑長時不用往下搜尋了,節省時間。

【程式碼】

#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;
}

【題意】

給定一棵樹,輸出每一層的葉子節點個數。

【解題思路】

用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;
}

【題意】

將一個數的各位數求和後,將每位數用英文表示。

【解題思路】

因為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;
}

【題意】

給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;
}

【題意】

給出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;
}

【題意】

坐電梯,剛開始停在第一層,上升一層需要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;
}

【題意】

給兩個多項式的項數、係數、指數,求兩個多項式相乘後的項數、係數、指數。

【解題思路】

用陣列的下標儲存多項式的係數,陣列的值儲存多項式的指數,然後當兩個陣列的相同下標的值都不為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;
}

【題意】

給出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;
}

【題意】

給出三行資料,代表三場比賽。每行有三個浮點整數,從左至右分別代表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;
}

【題意】

現已知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;
}

【題意】

給出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;
}

【題意】

如果一個數本身是素數,而且在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;
}

【題意】

模擬銀行的作息,銀行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;
}

【題意】

給定一個數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;
}

【題意】

已知一棵樹的後序和中序,輸出樹的層序。

【解題思路】

已知後序序列: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;
}

【題意】

給出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;
}

【題意】

某個數乘以兩倍之後看每位數的個數是否與原數相同。比如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;
}

【題意】

給定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;
}

【題意】

分成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;
}

【題意】

給出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;
}

【題意】

將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;
}

【題意】

求起點到終點的最短路徑最短距離和花費,要求首先路徑最短,其次花費最少,要輸出完整路徑。

【解題思路】

先通過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;
}