数据结构与算法训练:第二十三弹

这篇博客介绍了PAT编程竞赛中的四道题目,涉及字符串操作,如分数运算;排序算法,包括插入排序和归并排序的实现;多叉树的层次遍历;以及BFS在连通图体积求解中的应用。作者分享了代码实现和解题思路,并针对排序算法的优化进行了讨论。
摘要由CSDN通过智能技术生成

1. 知识点总结

耗时:2h28min

得分:99/100

知识点:字符串、最大公因数、插入排序和归并排序、多叉树的层次遍历、BFS连通图体积求解

题目难度知识点
1088 Rational Arithmetic🎯字符串、最大公因数
1089 Insert or Merge🎯🎯|✨插入排序和归并排序
1090 Highest Price in Supply Chain🎯多叉树的构建和层次遍历
1091 Acute Stroke🎯BFS

2. 分题题解

2.1 1088 Rational Arithmetic

不是很难,虽然代码量看着多~

主要是分数的运算,注意输出格式即可,需要留意一下除零的情况~

  • 首先getVal根据字符串获取分数的值以及正负情况
  • 接着AddDiff这些主要是按照分数运算规则求解答案
  • 对分数结构体Node输出时调用Print注意输出格式:最简分数形式
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
string str1,str2;
struct Node{
	bool neg=false;
	ll up;
	ll down;
};
Node num1,num2;
//求最大公因数 
ll gcd(ll a,ll b){
	if(a<b)swap(a,b);
	ll temp;
	while(b){
		temp=b;
		b=a%b;
		a=temp;
	}
	return a;
}
void getValue(string str,Node&num){
	if(str[0]=='-'){
		num.neg=true;
		str=str.substr(1,str.length());
	}
	sscanf(str.c_str(),"%lld/%lld",&num.up,&num.down);
	ll temp=gcd(num.up,num.down);
	num.up/=temp;
	num.down/=temp;
	if(num.neg){
		num.up=-num.up;
	}
}
void Print(Node num){
	if(num.neg){
		printf("(-");
	}
	if(num.up==0){
		printf("0");
	}else{
		ll out=num.up/num.down;
		ll res=num.up-out*num.down;
		if(out){
			printf("%lld",abs(out));
		}
		if(res){
			if(out){
				printf(" ");
			}
			printf("%lld/%lld",abs(res),abs(num.down));
		}
	}
	if(num.neg){
		printf(")");
	}
}
void Add(Node num1,Node num2){
	Node ans;
	// a/b + c/d= (a*d+b*c)/(b*d)
	ans.up=(num1.up*num2.down+num1.down*num2.up);
	ans.down=(num1.down*num2.down);
	if(ans.up<0)ans.neg=true;
	ll temp=gcd(abs(ans.up),ans.down);
	ans.up/=temp;
	ans.down/=temp;
	//输出答案 
	Print(num1);
	printf(" + ");
	Print(num2);
	printf(" = ");
	Print(ans);
	printf("\n");
}
void Diff(Node num1,Node num2){
	Node ans;
	//a/b - c/d= (a*d-b*c)/(b*d)
	ans.up=(num1.up*num2.down-num1.down*num2.up);
	ans.down=(num1.down*num2.down);
	if(ans.up<0)ans.neg=true;
	ll temp=gcd(abs(ans.up),ans.down);
	ans.up/=temp;
	ans.down/=temp;
	//输出答案 
	Print(num1);
	printf(" - ");
	Print(num2);
	printf(" = ");
	Print(ans); 
	printf("\n");
}
void Pro(Node num1,Node num2){
	Node ans;
	//a/b * c/d= a*c/(b*d)
	ans.up=(num1.up*num2.up);
	ans.down=(num1.down*num2.down);
	if(ans.up<0)ans.neg=true;
	ll temp=gcd(abs(ans.up),ans.down);
	ans.up/=temp;
	ans.down/=temp;
	//输出答案 
	Print(num1);
	printf(" * ");
	Print(num2);
	printf(" = ");
	Print(ans); 
	printf("\n");
}
void Quo(Node num1,Node num2){
	Node ans;
	if(num2.up==0){
		Print(num1);
		printf(" / ");
		Print(num2);
		printf(" = ");
		printf("Inf");
		return;
	}
	//a/b / c/d= a*d/(b*c)
	ans.up=(num1.up*num2.down);
	ans.down=(num1.down*num2.up);
	if(num1.neg&&!num2.neg||!num1.neg&&num2.neg){
		ans.neg=true;
	}
	ll temp=gcd(abs(ans.up),ans.down);
	ans.up/=temp;
	ans.down/=temp;
	//输出答案 
	Print(num1);
	printf(" / ");
	Print(num2);
	printf(" = ");
	Print(ans); 
}
int main(){
	cin>>str1>>str2;
	getValue(str1,num1);
	getValue(str2,num2);
	Add(num1,num2);
	Diff(num1,num2);
	Pro(num1,num2);
	Quo(num1,num2);
	return 0;
}

2.2 1089 Insert or Merge

主要考察插入排序和归并排序的具体实现步骤

模拟的时候卡在了归并排序上,最后第二个测试点被扣1分

24分代码:

#include<bits/stdc++.h>
using namespace std;
int N;
vector<int>v0,v1;
vector<int>temp;
bool insertSort(){
	temp=v0;
	bool flag=false;
	for(int i=1;i<N;i++){
		if(temp==v1){
			flag=true;
		}
		//一次迭代
		int pos=i;
		int value=temp[i];
		while(pos){
			temp[pos]=temp[pos-1];
			if(temp[pos]<value){
				break;
			}
			pos--;
		}
		temp[pos]=value;
		//一次迭代 
		if(flag){
			break;
		} 
	}
	return flag;
}
bool mergeSort(){
	bool flag=false;
	temp=v0;
	int block=2;
	while(block<N){
		if(temp==v1){
			flag=true;
		}
		for(int i=0;i<N;i+=block){
			if(i+block<=N){
				sort(temp.begin()+i,temp.begin()+i+block);
			}else{
				sort(temp.begin()+i,temp.end());
			}
		}
		if(flag&&temp!=v1){
			break;
		}
		block*=2;
	}
	
	return flag;
}
int main(){
	scanf("%d",&N);
	v0.resize(N);
	v1.resize(N);
	for(int i=0;i<N;i++){
		scanf("%d",&v0[i]);
	}
	for(int i=0;i<N;i++){
		scanf("%d",&v1[i]);
	}
	if(mergeSort()){
		printf("Merge Sort\n");
	}else{
		insertSort();
		printf("Insertion Sort\n");
	}
	for(int i=0;i<N;i++){
		if(i){
			printf(" ");
		}
		printf("%d",temp[i]);
	}
	return 0;
}

看了柳神的代码依然没有找到自己的merge哪里错了,但是测试后发现好像index2测试点既是insertSort又是mergeSort,心态炸裂,重新考虑了一下可能是插入排序从第二个下标点开始,也就是说如果v1==v0的时候,默认是mergeSort,顺利AC~

#include<bits/stdc++.h>
using namespace std;
int N;
vector<int>v0,v1;
vector<int>temp;
//插入排序
bool insertSort(){
	temp=v0;
	bool flag=false;
	for(int i=1;i<N;i++){
		if(i!=1&&temp==v1){
			flag=true;
		}
		//一次迭代
		int pos=i;
		int value=temp[i];
		while(pos&&temp[pos-1]>value){
			temp[pos]=temp[pos-1];
			pos--;
		}
		temp[pos]=value;
		//一次迭代 
		if(flag){
			break;
		} 
	}
	return flag;
}
bool mergeSort(){
	bool flag=false;
	temp=v0;
	int block=2;
	while(block<=N){
		if(temp==v1){
			flag=true;
		}
		for(int i=0;i<N;i+=block){
			if(i+block<=N){
				sort(temp.begin()+i,temp.begin()+i+block);
			}else{
				sort(temp.begin()+i,temp.end());
			}
		}
		if(flag){
			break;
		}
		block*=2;
	}
	
	return flag;
}
int main(){
	scanf("%d",&N);
	v0.resize(N);
	v1.resize(N);
	for(int i=0;i<N;i++){
		scanf("%d",&v0[i]);
	}
	for(int i=0;i<N;i++){
		scanf("%d",&v1[i]);
	}
	if(insertSort()){
		printf("Insertion Sort\n");
	}else{
		mergeSort();
		printf("Merge Sort\n");
	}
	for(int i=0;i<N;i++){
		if(i){
			printf(" ");
		}
		printf("%d",temp[i]);
	}
	return 0;
}

总之排序之后需要专门整理下知识点啦~

2.3 1090 Highest Price in Supply Chain

主要是考察静态多叉树的构建和层次遍历,这里将所有节点的索引都进行了+1处理方便利用vector存储遍历.最后输出注意从根节点所在层向下一个节点的时候不需要*(1+r/100)

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int N,tmp,root=0;
double p,r;
struct Node{
	vector<int>childs;
	int level=0;
};
vector<Node>nodes;
vector<int>level;
int max_level=0;
void levelTravel(int root){
	queue<int>q;
	q.push(root);
	int top;
	int level_cnt=0;
	while(!q.empty()){
		top=q.front();
		q.pop();
		level_cnt=nodes[top].level;
		if(level_cnt>max_level){
			max_level=level_cnt;
		}
		//printf("level %d:%d\n",level_cnt,top-1);
		level[level_cnt]++;
		for(int i=0;i<nodes[top].childs.size();i++){
			int id=nodes[top].childs[i];
			nodes[id].level=level_cnt+1;
			q.push(id);
		}
	}
}
int main(){
	scanf("%d%lf%lf",&N,&p,&r);
	nodes.resize(N+1);//0-N
	level.resize(N+1,0);
	for(int i=0;i<N;i++){
		scanf("%d",&tmp);
		nodes[tmp+1].childs.push_back(i+1);
	}
	levelTravel(root);
	for(int i=0;i<max_level-1;i++){
		p*=(1+r/100);
	}
	printf("%.2f %d",p,level[max_level]);
	return 0;
} 

2.4 1091 Acute Stroke

题目类似于二位数组找连通图,连通图面积大于一定阈值记录到cnt中,这里扩展到了三维的情况,值得注意的是,dfs会出现段错误,推荐使用BFS

#include<bits/stdc++.h>
using namespace std;
int N,M,L,T;
int tmp,cnt=0;
vector<vector<vector<bool> > >brain;
vector<vector<vector<bool> > >vis;
int di[]={0,0,0,0,1,-1};
int dx[]={0,0,1,-1,0,0};
int dy[]={1,-1,0,0,0,0};
int volume;
void dfs(int i,int x,int y){
	volume++;
	vis[i][x][y]=true;
	for(int v=0;v<6;v++){
		if(i+di[v]<0||i+di[v]>=L)continue;
		if(x+dx[v]<0||x+dx[v]>=N)continue;
		if(y+dy[v]<0||y+dy[v]>=M)continue;
		if(!vis[i+di[v]][x+dx[v]][y+dy[v]]&&brain[i+di[v]][x+dx[v]][y+dy[v]]){
			dfs(i+di[v],x+dx[v],y+dy[v]);
		}
	}
}
void bfs(int i,int x,int y){
	queue<int>qi,qx,qy;
	qi.push(i);
	qx.push(x);
	qy.push(y);
	vis[i][x][y]=true;
	while(!qi.empty()){
		i=qi.front();qi.pop();
		x=qx.front();qx.pop();
		y=qy.front();qy.pop();
		volume++;
		for(int v=0;v<6;v++){
			if(i+di[v]<0||i+di[v]>=L)continue;
			if(x+dx[v]<0||x+dx[v]>=N)continue;
			if(y+dy[v]<0||y+dy[v]>=M)continue;
			if(!vis[i+di[v]][x+dx[v]][y+dy[v]]&&brain[i+di[v]][x+dx[v]][y+dy[v]]){
				qi.push(i+di[v]);
				qx.push(x+dx[v]);
				qy.push(y+dy[v]);
				vis[i+di[v]][x+dx[v]][y+dy[v]]=true;
			}
		}
	}
}
int main(){
	scanf("%d%d%d%d",&N,&M,&L,&T);
	brain.resize(L);
	vis.resize(L);
	for(int i=0;i<L;i++){
		brain[i].resize(N);
		vis[i].resize(N);
		for(int j=0;j<N;j++){
			brain[i][j].resize(M);
			fill(brain[i][j].begin(),brain[i][j].end(),false);
			vis[i][j].resize(M);
			fill(vis[i][j].begin(),vis[i][j].end(),false);
		}
		for(int x=0;x<N;x++){
			for(int y=0;y<M;y++){
				scanf("%d",&tmp);
				if(tmp){
					brain[i][x][y]=true;
				}
			}
		}
	}
	for(int i=0;i<L;i++){
		for(int x=0;x<N;x++){
			for(int y=0;y<M;y++){
				if(!vis[i][x][y]&&brain[i][x][y]){
					volume=0;
                    //dfs(i,x,y);会出现段错误,25分
					bfs(i,x,y);
					if(volume>=T){
						cnt+=volume;
					}
				}
			}
		}
	}
	printf("%d",cnt);
	return 0; 
}

3. 参考资料

1089. Insert or Merge (25)-PAT甲级真题_柳婼的博客-CSDN博客

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值