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;
}
posted @ 2022-06-12 20:22  Ryomk  阅读(21)  评论(0编辑  收藏  举报