PAT甲级刷题日记(二)
1020 Tree Traversals
Thu Jun 9 18:19
Link
25分
这题做复杂了,因为我建树了…后来看了柳神的题解发现不用建树就可以做。做法是先通过“已知后序中序求前序”的方法得到前序序列,但是每个节点都需要加一个index(是层次序列的编号,求法和手动用数组建二叉堆很相像,左孩子=父亲*2,右孩子=父亲*2+1
,这里根节点下标是从1开始的),根据index对前序序列排序就可以得到层次遍历的序列。
已知后序与中序输出前序
摘录自柳神的博客:
后序:3, 4, 2, 6, 5, 1(左右根)
中序:3, 2, 4, 1, 6, 5(左根右)
分析:因为后序的最后一个总是根结点,令i在中序中找到该根结点,则i把中序分为两部分,左边是左子树,右边是右子树。因为是输出先序(根左右),所以先打印出当前根结点,然后打印左子树,再打印右子树。左子树在后序中的根结点为root – (end – i + 1),即为当前根结点-(右子树的个数+1)。左子树在中序中的起始点start为start,末尾end点为i – 1.右子树的根结点为当前根结点的前一个结点root – 1,右子树的起始点start为i+1,末尾end点为end。
输出的前序应该为:1, 2, 3, 4, 5, 6(根左右)
void pre(int root, int start, int end) { if(start > end) return ; int i = start; while(i < end && in[i] != post[root]) i++; printf("%d ", post[root]); pre(root - 1 - end + i, start, i - 1); pre(root - 1, i + 1, end); }
建树版AC代码:
#include <iostream> #include <cstdio> #include <cstdlib> #include <algorithm> #include <string> #include <string.h> #include <vector> #include <queue> using namespace std; #define N 35 int n; int post[N],in[N],lch[N],rch[N]; int level(int s1,int s2,int len){ // s1->in,s2->post if(s1>=n||s2>=n||len<0||len>n) return -1; int root=post[s2+len-1]; int pos=find(in,in+n,root)-in; if(pos==n||pos<s1||pos>=s1+len) return -1; lch[root]=level(s1,s2,pos-s1); rch[root]=level(pos+1,s2+pos-s1,s1+len-pos-1); return root; } void BFS(int root){ queue<int>q; printf("%d",root); if(lch[root]!=-1) q.push(lch[root]); if(rch[root]!=-1) q.push(rch[root]); while(!q.empty()){ root=q.front(); q.pop(); if(lch[root]!=-1) q.push(lch[root]); if(rch[root]!=-1) q.push(rch[root]); printf(" %d",root); } printf("\n"); } int main() { 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]); int root=level(0,0,n); BFS(root); return 0; }
1021 Deepest Root
Thu Jun 9 20:17
Link
25分
思路是:先用并查集判断图是否是连通的,如果连通就先随便找个点(我选定了点1),从这个点开始DFS一次,计算出另外n-1个点到点1的距离(即经过多少条边才能到达),然后找出距离的最大值以及距离点1最大的那个点的编号(可能不止一个,但是没关系,这里先找出一个),这时的最大值记为maxv。设这个点为x,那么这个x就一定是最长路径(可能不止一条)中的一个端点。然后从x开始再进行一次DFS,求出另外n-1个点到点x的距离,再找出最大值,这时的最大值就是最长路径的长度了,记为maxLen。然后,从1循环到n(保证答案从小到大输出),如果某个点满足它到1的距离等于maxv或者到x的距离等于maxLen,那么它就是最长路径的一个端点,直接输出即可。
注意n=1的情况,我是特判了的。
AC代码:
#include <iostream> #include <cstdio> #include <cstdlib> #include <algorithm> #include <string> #include <string.h> #include <vector> using namespace std; #define N 10010 int n,maxLen; int father[N],len[N]; vector<int>g[N]; bool vis[N]; int find_set(int x){ while(x!=father[x]){x=father[x]=father[father[x]];} return x; } void DFS(int cur,int s,int arr[]){ vis[cur]=true; arr[cur]=arr[s]+1; for(int i=0;i<g[cur].size();++i) if(!vis[g[cur][i]]) DFS(g[cur][i],cur,arr); } int main() { scanf("%d",&n); for(int i=1;i<=n;++i) father[i]=i; for(int i=1;i<=n-1;++i){ int u,v; scanf("%d%d",&u,&v); g[u].push_back(v); g[v].push_back(u); int fu=find_set(u),fv=find_set(v); if(fu!=fv) father[fu]=fv; } int cnt=0; for(int i=1;i<=n;++i) if(father[i]==i) cnt++; if(cnt>1){ printf("Error: %d components\n",cnt); return 0; } if(n==1){ printf("1\n"); return 0; } memset(father,-1,sizeof(father)); DFS(1,1,father); int maxv=0,cur=1; for(int i=2;i<=n;++i) if(father[i]>maxv){ maxv=father[i]; cur=i; } memset(vis,false,sizeof(vis)); memset(len,-1,sizeof(len)); DFS(cur,cur,len); for(int i=1;i<=n;++i) maxLen=max(maxLen,len[i]); for(int i=1;i<=n;++i) if(father[i]==maxv||len[i]==maxLen) printf("%d\n",i); return 0; }
1023 Have Fun with Numbers
Thu Jun 9 21:22
Link
20分
AC代码:
#include <iostream> #include <cstdio> #include <cstdlib> #include <algorithm> #include <string> #include <string.h> #include <vector> using namespace std; char s[25]; int num[25]; int v[10]; int main() { scanf("%s",s); int j=0; for(int i=strlen(s)-1;i>=0;--i){ num[++j]=(int)(s[i]-'0'); v[num[j]]++; num[j]<<=1; } for(int i=1;i<=j;++i){ num[i]+=num[i-1]/10; num[i-1]%=10; if(i-1>=1) v[num[i-1]]--; } v[num[j]%10]--; if(num[j]>=10){ num[j+1]=num[j]/10; num[j]%=10; j++; } bool flag=true; if(j>strlen(s)) flag=false; else{ for(int i=0;i<=9;++i) if(v[i]!=0){ flag=false; break; } } printf("%s\n",flag?"Yes":"No"); for(int i=j;i>=1;--i) printf("%d",num[i]); printf("\n"); return 0; }
1024 Palindromic Number
Fri Jun 10 21:17
Link
25分
原来输入的数是低位在前、高位在后的,为了方便进位,需要将它倒过来,于是我用int数组倒序存储,后来看了柳神的题解发现其实还有更简单的方法,那就是用string读入后直接reverse(s.begin(), s.end())
,在进行相加操作时也可以直接对字符进行相加,毕竟都是ASCII码嘛。判断是否需要进位,就直接判断s[i]>'9'
即可。而且用string存储还有个好处,那就是判断是否是回文串时,可以直接判断s==t
,其中字符串t是字符串s的reverse。
最后需要注意,如果给定的n就是一个回文数,那么一次相加操作都没有。我这里也写复杂了,其实直接从0遍历到k就行了。而且最后如果没有break(也就是在k步里没有得到回文数),那么此时应该输出k而不是i(我的代码里i在for外面定义的,因此跳出for时等于k+1)。总之,可以写成下面的简单形式:
cin >> s >> cnt; for(i = 0; i <= cnt; i++) { string t = s; reverse(t.begin(), t.end()); if(s == t || i == cnt) break; add(t); }
add
函数:
void add(string t) { int len = s.length(), carry = 0; for(int i = 0; i < len; i++) { s[i] = s[i] + t[i] + carry - '0'; carry = 0; if(s[i] > '9') { s[i] = s[i] - 10; carry = 1; } } if(carry) s += '1'; reverse(s.begin(), s.end()); }
AC代码:
#include <iostream> #include <cstdio> #include <cstdlib> #include <algorithm> #include <string> #include <string.h> #include <vector> using namespace std; char s[15]; int num[200],tmp[200]; int k,n; inline bool isPalindrome(){ for(int i=1;i<=(n>>1);++i) if(num[i]!=num[1+n-i]) return false; return true; } int main() { scanf("%s%d",s,&k); int i; for(i=strlen(s)-1;i>=0;--i) num[++n]=s[i]-'0'; if(isPalindrome()){ printf("%s\n0\n",s); return 0; } for(i=1;i<=k;++i){ for(int i=1;i<=n;++i) tmp[i]=num[i]+num[n+1-i]; for(int i=1;i<=n;++i) num[i]=tmp[i]; for(int i=0;i<n;++i){ num[i+1]+=num[i]/10; num[i]%=10; } if(num[n]>=10){ num[n+1]+=num[n]/10; num[n]%=10; n++; } if(isPalindrome()) break; } for(int j=n;j>=1;--j) printf("%d",num[i]); printf("\n%d\n",min(i,k)); return 0; }
1027 Colors in Mars
Sat Jun 11 17:16
Link
20分
简单题,无坑。但还是没有一次AC qwq
AC代码:
#include <iostream> #include <cstdio> #include <cstdlib> #include <algorithm> #include <string> #include <string.h> #include <vector> using namespace std; int r,g,b; char a[15]="0123456789ABC"; int main() { scanf("%d%d%d",&r,&g,&b); printf("#%c%c%c%c%c%c\n",a[r/13],a[r%13],a[g/13],a[g%13],a[b/13],a[b%13]); return 0; }
1029 Median
Sun Jun 12 20:20
Link
25分
AC代码:
#include <iostream> #include <cstdio> #include <cstdlib> #include <algorithm> #include <string> #include <string.h> #include <vector> using namespace std; int n1,n2,i,j,cnt,ans; int a[200010],b[200010]; int main() { scanf("%d",&n1); for(i=1;i<=n1;++i) scanf("%d",&a[i]); scanf("%d",&n2); for(j=1;j<=n2;++j) scanf("%d",&b[j]); int mid=(n1+n2+1)>>1; i=1,j=1; while(i<=n1&&j<=n2){ ans=a[i]<=b[j]?a[i++]:b[j++]; if(++cnt==mid) break; } if(cnt<mid&&i<=n1) ans=a[i-1+mid-cnt]; else if(cnt<mid&&j<=n2) ans=b[j-1+mid-cnt]; printf("%d\n",ans); return 0; }
本文作者:Ryomk
本文链接:https://www.cnblogs.com/preccrep/p/16360710.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步